home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2006 May / PCWMAY06.iso / Software / Toolkit / Songbird 0.1 / Songbird_0_1_0.exe / chrome / content / songbird_hack.js < prev    next >
Text File  |  2006-02-10  |  92KB  |  3,070 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. // 
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright⌐ 2006 Pioneers of the Inevitable LLC
  8. // http://songbirdnest.com
  9. // 
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the ôGPLö).
  12. // 
  13. // Software distributed under the License is distributed 
  14. // on an ôAS ISö basis, WITHOUT WARRANTY OF ANY KIND, either 
  15. // express or implied. See the GPL for the specific language 
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this 
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc., 
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. // 
  23. // END SONGBIRD GPL
  24. //
  25.  */
  26.  
  27. //
  28. //  Yes, I know this file is a mess.
  29. //
  30. //  Yes, I know we have to clean it up.
  31. //
  32. //  Yes, this will happen soon.
  33. //
  34. //  I promise.  Or something.
  35. //
  36. //                  - mig
  37. //
  38.  
  39.  
  40. try
  41. {
  42. const LOAD_FLAGS_BYPASS_HISTORY = 64;
  43.  
  44. // okay
  45. var thePlaylistReader = null;
  46.  
  47. // Hooray for event handlers!
  48. function myPlaybackEvent( key, value )
  49. {
  50. }
  51.  
  52. // Create a player remote with an explicit event handler.
  53. var myPlayerRemote = new CPlayerRemote( myPlaybackEvent );
  54. // I should remember to destruct him, eventually, but he was instantiated into the global scope.
  55.  
  56. theSongbirdStrings = document.getElementById( "songbird_strings" );
  57.  
  58. var SBServiceTreeListener = {
  59.  
  60.   m_CurrentSelection: "",
  61.   m_Tree: null,
  62.   
  63.   QueryInterface : function(aIID) {
  64.     if (!aIID.equals(Components.interfaces.nsIXULBuilderListener) &&
  65.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  66.         !aIID.equals(Components.interfaces.nsISupports)) 
  67.     {
  68.       throw Components.results.NS_ERROR_NO_INTERFACE;
  69.     }
  70.     return this;
  71.   },
  72.   
  73.   willRebuild : function( builder )
  74.   {
  75.     try
  76.     {
  77.       // Save selection
  78.       if ( this.m_Tree && ( this.m_Tree.currentIndex != -1 ) )
  79.       {
  80.         var column = this.m_Tree.columns ? this.m_Tree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  81.         this.m_CurrentSelection = this.m_Tree.view.getCellText( this.m_Tree.currentIndex, column );
  82.       }
  83.       saveCollapsedStates(this.m_Tree);
  84.     }
  85.     catch( err )
  86.     {
  87.       alert( err );
  88.     }
  89.   },
  90.   
  91.   didRebuild : function( builder )
  92.   {
  93.     try
  94.     {
  95.       // Restore selection
  96.       if ( this.m_Tree && ( this.m_Tree.currentIndex == -1 ) && ( this.m_CurrentSelection.length > 0 ) )
  97.       {
  98.         var column = this.m_Tree.columns ? this.m_Tree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  99.         for ( var i = 0; i < this.m_Tree.view.rowCount; i++ )
  100.         {
  101.           if ( this.m_CurrentSelection == this.m_Tree.view.getCellText( i, column ) )
  102.           {
  103.             this.m_Tree.view.selection.currentIndex = i;
  104.             this.m_Tree.view.selection.select( i );
  105.             this.m_CurrentSelection = "";
  106.             break;
  107.           }
  108.         }
  109.       }
  110.       this.m_CurrentSelection = "";
  111.       restoreCollapsedStates(this.m_Tree);
  112.     }
  113.     catch( err )
  114.     {
  115.       alert( err );
  116.     }
  117.   }
  118. }
  119.  
  120. function saveCollapsedStates( tree )
  121. {
  122.   try
  123.   {
  124.     var col = tree.columns ? tree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  125.     for (var i=0;i<tree.view.rowCount;i++)
  126.     {
  127.       if (tree.view.isContainer(i))
  128.       {
  129.         var item_url = tree.view.getCellText( i, col );
  130.         var item_remote = new sbIDataRemote( "collapsed_" + tree.id + "_" + item_url );
  131.         item_remote.SetValue(!tree.view.isContainerOpen(i));
  132.       }
  133.     }
  134.   }
  135.   catch (err)
  136.   {
  137.     alert('songbird_hack - saveCollapsedStates - ' + err);
  138.   }
  139. }
  140.  
  141. function restoreCollapsedStates( tree )
  142. {
  143.   try
  144.   {
  145.     var col = tree.columns ? tree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  146.     for (var i=0;i<tree.view.rowCount;i++)
  147.     {
  148.       if (tree.view.isContainer(i))
  149.       {
  150.         var item_url = tree.view.getCellText( i, col );
  151.         var item_remote = new sbIDataRemote( "collapsed_" + tree.id + "_" + item_url );
  152.         if (item_remote.GetIntValue())
  153.         {
  154.           if (tree.view.isContainerOpen(i))
  155.           {
  156.             tree.view.toggleOpenState(i);
  157.           }
  158.         }
  159.       } 
  160.     }
  161.   }
  162.   catch (err)
  163.   {
  164.     alert('songbird_hack - restoreCollapsedStates - ' + err);
  165.   }
  166. }
  167.  
  168. var SBWindowMinMaxCB = 
  169. {
  170.   // Shrink until the box doesn't match the window, then stop.
  171.   GetMinWidth: function()
  172.   {
  173.     // What we'd like it to be
  174.     var retval = 750;
  175.     // However, if in resizing the window size is different from the document's box object
  176.     if (window.innerWidth != document.getElementById('window_parent').boxObject.width)
  177.     { 
  178.       // That means we found the document's min width.  Because you can't query it directly.
  179.       retval = document.getElementById('window_parent').boxObject.width - 1;
  180.     }
  181.     return retval;
  182.   },
  183.  
  184.   GetMinHeight: function()
  185.   {
  186.     // What we'd like it to be
  187.     var retval = 400;
  188.     // However, if in resizing the window size is different from the document's box object
  189.     if (window.innerHeight != document.getElementById('window_parent').boxObject.height)
  190.     { 
  191.       // That means we found the document's min width.  Because you can't query it directly.
  192.       retval = document.getElementById('window_parent').boxObject.height - 1;
  193.     }
  194.     return retval;
  195.   },
  196.  
  197.   GetMaxWidth: function()
  198.   {
  199.     return -1;
  200.   },
  201.  
  202.   GetMaxHeight: function()
  203.   {
  204.     return -1;
  205.   },
  206.  
  207.   QueryInterface : function(aIID)
  208.   {
  209.     if (!aIID.equals(Components.interfaces.sbIWindowMinMaxCallbacl) &&
  210.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  211.         !aIID.equals(Components.interfaces.nsISupports)) 
  212.     {
  213.       throw Components.results.NS_ERROR_NO_INTERFACE;
  214.     }
  215.     
  216.     return this;
  217.   }
  218. }
  219.  
  220. function setMinMaxCallback()
  221. {
  222.   var windowMinMax = Components.classes["@songbird.org/Songbird/WindowMinMax;1"].getService(Components.interfaces.sbIWindowMinMax);
  223.   windowMinMax.SetCallback(document, SBWindowMinMaxCB);
  224. }
  225.  
  226. function checkAltF4(evt)
  227. {
  228.   if (evt.keyCode == 0x73 && evt.altKey) 
  229.   {
  230.     evt.preventDefault();
  231.     quitApp();
  232.   }
  233. }
  234.  
  235. /**
  236. * Convert a string containing binary values to hex.
  237. */
  238. function binaryToHex(input)
  239. {
  240.   var result = "";
  241.   
  242.   for (var i = 0; i < input.length; ++i) 
  243.   {
  244.     var hex = input.charCodeAt(i).toString(16);
  245.   
  246.     if (hex.length == 1)
  247.       hex = "0" + hex;
  248.   
  249.     result += hex;
  250.   }
  251.   
  252.   return result;
  253. }
  254.  
  255. function SBFirstRunPong()
  256. {
  257.   const pongURL = "http://www.songbirdnest.com/player/pong";
  258.   
  259.   var firstRun = new sbIDataRemote("application.first_run");
  260.   var isFirst = firstRun.GetValue();
  261.  
  262.   if(isFirst == "")
  263.   {
  264.     var playerUUID = new sbIDataRemote("application.uuid");
  265.  
  266.     var newUUID = playerUUID.GetValue()
  267.     if(newUUID == "")
  268.     {
  269.       var aUUIDGenerator = Components.classes["@mozilla.org/uuid-generator;1"].createInstance(Components.interfaces.nsIUUIDGenerator);
  270.  
  271.       newUUID = aUUIDGenerator.generateUUID();
  272.       playerUUID.SetValue(newUUID);
  273.     }
  274.  
  275.     var pongRequest = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
  276.     var pongHash = Components.classes["@mozilla.org/security/hash;1"].createInstance(Components.interfaces.nsICryptoHash);
  277.     var inputStream = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance(Components.interfaces.nsIStringInputStream);
  278.     const confirmShake = "army of darkness rulez";
  279.     
  280.     inputStream.setData(newUUID, -1);
  281.     
  282.     pongHash.initWithString("SHA1");
  283.     pongHash.updateFromStream(inputStream, -1);
  284.     var uuidHash = binaryToHex(pongHash.finish(false));
  285.     
  286.     confirmShake = uuidHash + confirmShake;
  287.     inputStream.setData(confirmShake, -1);
  288.     
  289.     pongHash.initWithString("SHA1");
  290.     pongHash.updateFromStream(inputStream, -1);
  291.     var confirmHash = binaryToHex(pongHash.finish(false));
  292.    
  293.     var message = "i=" + uuidHash + "&c=" + confirmHash;
  294.     var requestURL = pongURL + "?" + message;
  295.      
  296.     pongRequest.open("GET", requestURL, false);
  297.     pongRequest.send(null);
  298.     
  299.     if(pongRequest.status == 204)
  300.     {
  301.       dump("Success!!!");
  302.       firstRun.SetValue("false");
  303.     }
  304.     else
  305.     {
  306.       dump("Failure!!!");
  307.     }
  308.   }
  309. }
  310.  
  311. //
  312. // Core Wrapper Initialization (in XUL, this must happen after the entire page loads). 
  313. //
  314. var Poll = null;
  315. function SBInitialize()
  316. {
  317.   dump("SBInitialize *** \n");
  318.  
  319.   SBFirstRunPong();
  320.  
  321.   const MediaLibrary = new Components.Constructor("@songbird.org/Songbird/MediaLibrary;1", "sbIMediaLibrary");
  322.   const PlaylistManager = new Components.Constructor("@songbird.org/Songbird/PlaylistManager;1", "sbIPlaylistManager");
  323.   const PlaylistReaderManager = new Components.Constructor("@songbird.org/Songbird/PlaylistReaderManager;1", "sbIPlaylistReaderManager");
  324.   thePlaylistReader = (new PlaylistReaderManager()).QueryInterface(Components.interfaces.sbIPlaylistReaderManager);
  325.  
  326.   try
  327.   {
  328.     onWindowLoadSize();
  329.     setMinMaxCallback();
  330.     SBInitPlayerControls();
  331.  
  332.     if (window.addEventListener)
  333.       window.addEventListener("keydown", checkAltF4, true);
  334.  
  335.     // Make sure we have a fake database in which to play
  336.     aDBQuery = Components.classes["@songbird.org/Songbird/DatabaseQuery;1"];
  337.     if (aDBQuery)
  338.     {
  339.       aDBQuery = aDBQuery.createInstance();
  340.       aDBQuery = aDBQuery.QueryInterface(Components.interfaces.sbIDatabaseQuery);
  341.       aDBQuery.SetAsyncQuery(false);
  342.       aDBQuery.SetDatabaseGUID("testdb-0000");
  343.       aDBQuery.AddQuery("create table test (idx integer primary key autoincrement, url text, name text, tim text, artist text, album text, genre text)");
  344.       aDBQuery.AddQuery("create index testindex on test(idx, url, name, tim, artist, album, genre)");
  345.       
  346.       var ret = aDBQuery.Execute();
  347.       
  348.       // If it actually worked, that means we created the database
  349.       // ask the user if they would like to fill their empty bucket.
  350.       if ( ret == 0 )
  351.       {
  352.         theMediaScanIsOpen.SetValue( true );
  353.         setTimeout( SBScanMedia, 1000 );
  354.       }
  355.     }
  356.     
  357.     // Install listeners on the main pane.
  358.     var theMainPane = document.getElementById("frame_main_pane");
  359.     if (!mainpane_listener_set)
  360.     {
  361.       mainpane_listener_set = false;
  362.       if (theMainPane.addEventListener) {
  363.         theMainPane.addEventListener("DOMContentLoaded", onMainPaneLoad, false);
  364.         theMainPane.addEventListener("unload", onMainPaneUnload, true);
  365.         theMainPane.addProgressListener(SBDocStartListener);
  366.       }
  367.     }
  368.     
  369.     // Do something weird to select the first service tree item.
  370.     
  371.     var lastSelection = -1; 
  372.     if ( SBDataGetValue( "servicetree.selection" ) == "" )
  373.     {
  374.       lastSelection = 0; 
  375.     }
  376.     var theServiceTree = document.getElementById( 'frame_service_tree' );   
  377.     restoreServicesCollapsedStates();
  378.     theServiceTree.view.selection.currentIndex = lastSelection;
  379.     theServiceTree.view.selection.select( lastSelection );
  380.     SBServiceTreeListener.m_Tree = theServiceTree;
  381.     theServiceTree.builder.addListener( SBServiceTreeListener );
  382. //    alert ( SBServiceTreeListener.m_Tree + " " + SBServiceTreeListener.m_Tree.currentIndex );
  383.     onServiceTreeRestoreSize();
  384.  
  385.     var lastURI = SBDataGetValue( "browser.uri" );
  386.     if ( lastURI != "" )
  387.     {
  388.       LaunchMainPaneURL( lastURI );
  389.     }
  390.  
  391.     theWebPlaylist = document.getElementById( "playlist_web" );
  392.     theWebPlaylist.addEventListener( "playlist-play", onPlaylistPlay, true );
  393. // no!    theWebPlaylist.addEventListener( "playlist-edit", onPlaylistEdit, true );
  394.     theWebPlaylist.addEventListener( "command", onPlaylistContextMenu, false );  // don't force it!
  395.     theWebPlaylist.setDnDSourceTracker(sbDnDSourceTracker);
  396.     theWebPlaylistQuery = null;
  397.     
  398.     // Poll the playlist source every 250ms to drive the display update (STOOOOPID!)
  399.     Poll = new sbIPlaylistsource();
  400.     NumPlaylistItemsRemote = new sbIDataRemote( "playlist.numitems" );
  401.     NumPlaylistItemsRemote.SetValue( "" );
  402.     function PFU()
  403.     {
  404.       try
  405.       {
  406.         // Tell the Playlistsource it is allowed to update its observers if it wants.
  407.         if ( ! isPlaylistEditShowing )    
  408.         {
  409. //          Poll.UpdateObservers();
  410.         }
  411.         
  412.         // Display the number of items in the currently viewed playlist.
  413.         var tree_ref = "";
  414.         var display_string = "";
  415.         // thePlaylistTree is non-null when a playlist is showing.
  416.         if ( thePlaylistTree )
  417.         {
  418.           tree_ref = thePlaylistTree.getAttribute( "ref" );
  419.         }
  420.         else if ( theWebPlaylistQuery )
  421.         {
  422.           // If there's a web playlist query, then we can pop the webplaylist.
  423.           var mediafound = "Media Found";
  424.           try
  425.           {
  426.             mediafound = theSongbirdStrings.getString("faceplate.mediafound");
  427.           } catch(e) {}
  428.           var pct = parseInt( SBDataGetValue( "webplaylist.current" ) * 100 / SBDataGetValue( "webplaylist.total" ) );
  429.           if ( pct < 100 )
  430.           {
  431.             display_string = mediafound + " " + pct + "%";
  432.           }
  433.           else
  434.           {
  435.             tree_ref = theWebPlaylist.ref;
  436.           }
  437.         }
  438.         
  439.         if ( tree_ref.length )
  440.         {
  441.           var rows = Poll.GetRefRowCount( tree_ref );
  442.           if ( rows > 0 )
  443.           {
  444.             var items = "items";
  445.             try
  446.             {
  447.               items = theSongbirdStrings.getString("faceplate.items");
  448.             } catch(e) {}
  449.             display_string = rows + " " + items;
  450.           }
  451.         }
  452.         
  453.         NumPlaylistItemsRemote.SetValue( display_string );
  454.       }
  455.       catch ( err )
  456.       {
  457.         alert( err );
  458.       }
  459.     }
  460.     setInterval( PFU, 500 );
  461.  
  462. //    var the_url = "ftp://ftp.openbsd.org/pub/OpenBSD/songs";
  463. //    var the_url = "http://www.blogotheque.net/mp3/";
  464. //    var the_url = "file:///c:\\vice.html";
  465. //    var the_url = "http://odeo.com/channel/38104/rss";
  466. //    var the_url = "http://takeyourmedicinemp3.blogspot.com/atom.xml";
  467. //    var success = thePlaylistReader.AutoLoad(the_url, "songbird", ConvertUrlToDisplayName( the_url ), "http", the_url, "", null);
  468.   }
  469.   catch(err)
  470.   {
  471.     alert(err);
  472.   }
  473.  
  474. }
  475.  
  476.  
  477. function SBUninitialize()
  478. {
  479.   var windowMinMax = Components.classes["@songbird.org/Songbird/WindowMinMax;1"].getService(Components.interfaces.sbIWindowMinMax);
  480.   windowMinMax.ResetCallback(document);
  481. }
  482.  
  483. //
  484. // XUL Event Methods
  485. //
  486.  
  487. // The background image allows us to move the window around the screen
  488. function onBkgDown( theEvent ) 
  489. {
  490.   var windowDragger = Components.classes["@songbird.org/Songbird/WindowDragger;1"].getService(Components.interfaces.sbIWindowDragger);
  491.   windowDragger.BeginWindowDrag(0); // automatically ends
  492. }
  493. function onBkgUp( ) 
  494. {
  495.   var root = "window." + document.documentElement.id;
  496.   SBDataSetValue( root + ".x", document.documentElement.boxObject.screenX );
  497.   SBDataSetValue( root + ".y", document.documentElement.boxObject.screenY );
  498. }
  499.  
  500. // old version, just in case
  501. /*var trackerBkg = false;
  502. var offsetScrX = 0;
  503. var offsetScrY = 0;
  504. function onBkgDown( theEvent ) 
  505. {
  506.   trackerBkg = true;
  507.   offsetScrX = document.defaultView.screenX - theEvent.screenX;
  508.   offsetScrY = document.defaultView.screenY - theEvent.screenY;
  509.   document.addEventListener( "mousemove", onBkgMove, true );
  510. }
  511. function onBkgMove( theEvent ) 
  512. {
  513.   if ( trackerBkg )
  514.   {
  515.     document.defaultView.moveTo( offsetScrX + theEvent.screenX, offsetScrY + theEvent.screenY );
  516.   }
  517. }
  518. function onBkgUp( ) 
  519. {
  520.   if ( trackerBkg )
  521.   {
  522.     trackerBkg = false;
  523.     document.removeEventListener( "mousemove", onBkgMove, true );
  524.   }
  525. }*/
  526.  
  527.  
  528. var URL = new sbIDataRemote("faceplate.play.url");
  529. var thePlaylistIndex = new sbIDataRemote( "playlist.index" );
  530. var seen_playing = new sbIDataRemote("faceplate.seenplaying");
  531.  
  532. var theTitleText = new sbIDataRemote( "metadata.title" );
  533. var theArtistText = new sbIDataRemote( "metadata.artist" );
  534. var theAlbumText = new sbIDataRemote( "metadata.album" );
  535. var theStatusText = new sbIDataRemote( "faceplate.status.text" );
  536. var theStatusStyle = new sbIDataRemote( "faceplate.status.style" );
  537.  
  538. // Help
  539. function onHelp()
  540. {
  541.   alert( "Aieeeeee, ayudame!" );
  542. }
  543.  
  544. var theCurrentTrackInterval = null;
  545. function onCurrentTrack()
  546. {
  547.   if ( theCurrentTrackInterval )
  548.   {
  549.     clearInterval( theCurrentTrackInterval );
  550.   }
  551.   if ( ! thePlaylistTree )
  552.   {
  553.     // This needs to eventually load the "current playing playlist"
  554.     LaunchMainPaneURL( "chrome://rmp_demo/content/main_pane/main_pane.xul?library" );
  555.     theCurrentTrackInterval = setInterval( onCurrentTrack, 500 );
  556.   }
  557.   else
  558.   {
  559.     SBSyncPlaylistIndex();
  560.   }
  561. }
  562.  
  563. var FaceplateStateData = new sbIDataRemote( "faceplate.state" );
  564.  
  565. function onNextService()
  566. {
  567.   FaceplateStateData.SetValue( ( FaceplateStateData.GetIntValue() + 1 ) % 2 ); // can't use boolean, must use integer logic
  568. }
  569.  
  570. // onServiceTreeResize
  571. function onServiceTreeResize()
  572. {
  573.   var theServiceTree = document.getElementById( "frame_service_tree" );
  574.   SBDataSetValue( "servicetree.width", theServiceTree.width );
  575.   SBDataSetValue( "servicetree.collapsed", theServiceTree.nextSibling.getAttribute( "state" ) == "collapsed" );
  576. }
  577.  
  578. // onServiceTreeRestoreSize
  579. function onServiceTreeRestoreSize()
  580. {
  581.   var theServiceTree = document.getElementById( "frame_service_tree" );
  582.   var width = SBDataGetValue( "servicetree.width" );
  583.   if ( width != "" )
  584.   {
  585.     theServiceTree.width = width;
  586.     theServiceTree.nextSibling.setAttribute( "state", SBDataGetIntValue( "servicetree.collapsed" ) ? "collapsed" : "open" );
  587.   }
  588. }
  589.  
  590. // onServiceTreeSelect
  591. var UrlFromServicePane = false;
  592. function onServiceTreeSelect( theEvent )
  593. {
  594.   try
  595.   { 
  596.     var theServiceTree = document.getElementById( "frame_service_tree" );
  597.     
  598.     // multiple selection on service tree only happen during the highlighting of an item in drag over, don't switch to the service
  599.     if (theServiceTree.getAttribute("seltype") == "multiple") return;
  600.     SBDataSetValue( "servicetree.selection", theServiceTree.currentIndex );
  601.     if ( theServiceTree.currentIndex >= 0 )
  602.     {
  603.       // Find the column. 
  604.       var urlcolumn = theServiceTree.columns ? theServiceTree.columns["url"] : "url";
  605.       
  606.       // Get the text of the hidden tree cell, this contains the url.
  607.       var tree_url = theServiceTree.view.getCellText( theServiceTree.currentIndex, urlcolumn );
  608.       
  609.       if ( tree_url.length > 0 )
  610.       {
  611.         UrlFromServicePane = true;
  612.         LaunchMainPaneURL( tree_url );
  613.       }
  614.     }
  615.   }
  616.   catch(err)
  617.   {
  618.     alert( "onServiceTreeSelect - " + err);
  619.   }
  620.   
  621. }
  622.  
  623. function onServiceTreeClick( theEvent )
  624. {
  625.   saveServicesCollapsedStates();
  626. }
  627.  
  628. function saveServicesCollapsedStates()
  629. {
  630.   var theServiceTree = document.getElementById( "frame_service_tree" );
  631.   saveCollapsedStates(theServiceTree);
  632. }
  633.  
  634. function restoreServicesCollapsedStates()
  635. {
  636.   var theServiceTree = document.getElementById( "frame_service_tree" );
  637.   restoreCollapsedStates(theServiceTree);
  638. }
  639.  
  640. // onServiceTreeContext
  641. function onServiceTreeContext( theEvent )
  642. {
  643.   try
  644.   { 
  645.     var theServiceTree = document.getElementById( "frame_service_tree" );
  646.     // First, get the row clicked.
  647.     var obj = {}; 
  648.     var row = {};
  649.     var col = {};
  650.     theServiceTree.treeBoxObject.getCellAt( theEvent.clientX, theEvent.clientY, row, col, obj );
  651.  
  652.     row = row.value;    
  653.     
  654.     if ( row >= 0 )
  655.     {
  656.       // Find the selected element
  657.       var element = theServiceTree.contentView.getItemAtIndex( row );
  658.       var properties = element.getAttribute( "properties" ).split(" ");
  659.       if ( properties.length > 0 )
  660.       {
  661.         // The first property is the type.  Later strings are specific to the type.
  662.         switch ( properties[ 0 ] )
  663.         {
  664.           case "playlist":
  665.             onServiceTreeContextPlaylist( theEvent, properties );
  666.             break;
  667.           default:
  668.             onServiceTreeContextDefault( theEvent, properties );
  669.             break;
  670.         }
  671.       }
  672.     }
  673.     else
  674.     {
  675.       onServiceTreeContextNone( theEvent );
  676.     }
  677.   }
  678.   catch(err)
  679.   {
  680.     alert( "onServiceTreeSelect - " + err);
  681.   }
  682. }
  683.  
  684. function onServiceTreeContextPlaylist( theEvent, properties )
  685. {
  686.   if ( properties.length >= 5 )
  687.   {
  688.     var table = properties[ 1 ];
  689.     var guid = properties[ 2 ];
  690.     var type = properties[ 3 ];
  691.     var base_type = properties[ 4 ];
  692.     
  693.     // From these 4 pieces of data, we're going to have to do some idiotically complex stuff.
  694.     // Eventually, we'll register a sbIPlaylistCommands with the Servicesource
  695.     
  696.     // For now, make a set of short-circuits to protect our special playlists
  697.     if ( table == WEB_PLAYLIST_TABLE && guid == WEB_PLAYLIST_CONTEXT )
  698.     {
  699.       return;
  700.     }
  701.     if ( type == "transfer" && base_type == "simple" )
  702.     {
  703.       return;
  704.     }
  705.     var theServiceTreePlaylistPopup = document.getElementById( "service_popup_playlist" );
  706.     if ( base_type == "smart" )
  707.     {
  708.       theServiceTreePlaylistPopup = document.getElementById( "service_popup_smart" );
  709.     }
  710.     if ( base_type == "dynamic" )
  711.     {
  712.       theServiceTreePlaylistPopup = document.getElementById( "service_popup_smart" );
  713.     }
  714.     theServiceTreePlaylistPopup.setAttribute( "sb_table", table );
  715.     theServiceTreePlaylistPopup.setAttribute( "sb_guid", guid );
  716.     theServiceTreePlaylistPopup.setAttribute( "sb_type", type );
  717.     theServiceTreePlaylistPopup.setAttribute( "sb_base_type", base_type );
  718.     if ( theServiceTreePlaylistPopup )
  719.     {
  720.       theServiceTreePlaylistPopup.showPopup( document.documentElement, theEvent.screenX, theEvent.screenY, "context", null, null, null );
  721.     }
  722.   }
  723. }
  724.  
  725. function onServiceTreeContextDefault( theEvent, properties )
  726. {
  727. }
  728.  
  729. function onServiceTreeContextNone( theEvent )
  730. {
  731.   var theServiceTreePlaylistPopup = document.getElementById( "service_popup_none" );
  732.   if ( theServiceTreePlaylistPopup )
  733.   {
  734.     theServiceTreePlaylistPopup.showPopup( document.documentElement, theEvent.screenX, theEvent.screenY, "context", null, null, null );
  735.   }
  736. }
  737.  
  738. function onServiceTreeCommand( theEvent )
  739. {
  740.   if ( theEvent && theEvent.target )
  741.   {
  742.     // These attribs get set when the menu is popped up on a playlist.
  743.     var label = theEvent.target.parentNode.getAttribute( "label" );
  744.     var guid = theEvent.target.parentNode.getAttribute( "sb_guid" );
  745.     var table = theEvent.target.parentNode.getAttribute( "sb_table" );
  746.     var type = theEvent.target.parentNode.getAttribute( "sb_type" );
  747.     var base_type = theEvent.target.parentNode.getAttribute( "sb_base_type" );
  748.     switch ( theEvent.target.id )
  749.     {
  750.       case "service_popup_new":
  751.         SBNewPlaylist();
  752.       break;
  753.       case "service_popup_new_smart":
  754.         SBNewSmartPlaylist();
  755.       break;
  756.       case "service_popup_new_remote":
  757.         SBSubscribe( "", "", "", "" );
  758.       break;
  759.       
  760.       case "playlist_context_smartedit":
  761.         if ( base_type == "smart" )
  762.         {
  763.           if ( guid && guid.length > 0 && table && table.length > 0 )
  764.           {
  765.             SBNewSmartPlaylist( guid, table );
  766.           }
  767.         }
  768.         if ( base_type == "dynamic" )
  769.         {
  770.           if ( guid && guid.length > 0 && table && table.length > 0 )
  771.           {
  772.             SBSubscribe( type, guid, table, label );
  773.           }
  774.         }
  775.       break;
  776.       
  777.       case "playlist_context_rename":
  778.         if ( guid && guid.length > 0 && table && table.length > 0 )
  779.         {
  780.           onServiceEdit();
  781.         }
  782.       break;
  783.       
  784.       case "playlist_context_remove":
  785.         if ( guid && guid.length > 0 && table && table.length > 0 )
  786.         {
  787.           // Assume we'll need this...
  788.           const PlaylistManager = new Components.Constructor("@songbird.org/Songbird/PlaylistManager;1", "sbIPlaylistManager");
  789.           var aPlaylistManager = new PlaylistManager();
  790.           aPlaylistManager = aPlaylistManager.QueryInterface(Components.interfaces.sbIPlaylistManager);
  791.           var aDBQuery = new sbIDatabaseQuery();
  792.           
  793.           aDBQuery.SetAsyncQuery(false);
  794.           aDBQuery.SetDatabaseGUID(guid);
  795.  
  796.           switch ( base_type )
  797.           {
  798.             case "simple":
  799.               aPlaylistManager.DeleteSimplePlaylist(table, aDBQuery);
  800.               break;
  801.             case "dynamic":
  802.               aPlaylistManager.DeleteDynamicPlaylist(table, aDBQuery);
  803.               break;
  804.             case "smart":
  805.               aPlaylistManager.DeleteSmartPlaylist(table, aDBQuery);
  806.               break;
  807.             default:
  808.               aPlaylistManager.DeletePlaylist(table, aDBQuery);
  809.               break;
  810.           }
  811.         }
  812.       break;
  813.     }
  814.   }
  815. }
  816.  
  817. var theServiceTreeScanItems = new Array();
  818. var theServiceTreeScanCount = 0;
  819. function SBScanServiceTreeNewEntryEditable()
  820. {
  821.   var theServiceTree = document.getElementById( "frame_service_tree" );
  822.   theServiceTreeScanItems.length = 0;
  823.   theServiceTreeScanCount = 0;
  824.   
  825.   // Go get all the current service tree urls.
  826.   for ( var i = 0; i < theServiceTree.view.rowCount; i++ )
  827.   {
  828.     theServiceTreeScanItems.push( theServiceTree.contentView.getItemAtIndex( i ).getAttribute( "url" ) );
  829.   }
  830. }
  831.  
  832. function SBScanServiceTreeNewEntryStart()
  833. {
  834.   setTimeout( SBScanServiceTreeNewEntryCallback, 500 );
  835. }
  836.  
  837. function SBScanServiceTreeNewEntryCallback()
  838. {
  839.   var theServiceTree = document.getElementById( "frame_service_tree" );
  840.   
  841.   if ( ++theServiceTreeScanCount > 10 )
  842.   {
  843.     return; // don't loop more than 1 second.
  844.   }
  845.   
  846.   // Go through all the current service tree items.
  847.   var done = false;
  848.   for ( var i = 0; i < theServiceTree.view.rowCount; i++ )
  849.   {
  850.     var found = false;
  851.     var url = theServiceTree.contentView.getItemAtIndex( i ).getAttribute( "url" );
  852.     // Match them against the scan items
  853.     for ( var j = 0; j < theServiceTreeScanItems.length; j++ )
  854.     {
  855.       if ( url == theServiceTreeScanItems[ j ] )
  856.       {
  857.         found = true;
  858.         break;
  859.       }
  860.     }
  861.     // Right now, only songbird playlists are editable.
  862.     if ( ( ! found ) && ( url.indexOf( ",songbird" ) != -1 ) )
  863.     {
  864.       // This must be the new one?
  865.       theServiceTree.view.selection.currentIndex = i;
  866.       theServiceTree.view.selection.select( i );
  867.       onServiceEdit();
  868.       done = true;
  869.       break;
  870.     }
  871.   }
  872.   if ( ! done )
  873.   {
  874.     setTimeout( SBScanServiceTreeNewEntryCallback, 100 );
  875.   }
  876. }
  877.  
  878. function onServiceEdit()
  879. {
  880.   try
  881.   {
  882.     var theServiceTree = document.getElementById( "frame_service_tree" );
  883.     if ( theServiceTree && theServiceTree.currentIndex > -1 )
  884.     {
  885.       var column = theServiceTree.columns ? theServiceTree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  886.       var cell_text = theServiceTree.view.getCellText( theServiceTree.currentIndex, column );
  887.  
  888.       // This is nuts!
  889.       var text_x = {}, text_y = {}, text_w = {}, text_h = {}; 
  890.       theServiceTree.treeBoxObject.getCoordsForCellItem( theServiceTree.currentIndex, column, "text",
  891.                                                           text_x , text_y , text_w , text_h );
  892.       var cell_x = {}, cell_y = {}, cell_w = {}, cell_h = {}; 
  893.       theServiceTree.treeBoxObject.getCoordsForCellItem( theServiceTree.currentIndex, column, "cell",
  894.                                                           cell_x , cell_y , cell_w , cell_h );
  895.       var image_x = {}, image_y = {}, image_w = {}, image_h = {}; 
  896.       theServiceTree.treeBoxObject.getCoordsForCellItem( theServiceTree.currentIndex, column, "image",
  897.                                                           image_x , image_y , image_w , image_h );
  898.       var twisty_x = {}, twisty_y = {}, twisty_w = {}, twisty_h = {}; 
  899.       theServiceTree.treeBoxObject.getCoordsForCellItem( theServiceTree.currentIndex, column, "twisty",
  900.                                                           twisty_x , twisty_y , twisty_w , twisty_h );
  901.       var out_x = {}, out_y = {}, out_w = {}, out_h = {};
  902.       
  903.       out_x = text_x;
  904.       out_y = cell_y;
  905.       out_w.value = cell_w.value - twisty_w.value - image_w.value;
  906.       out_h = cell_h;
  907.       
  908.       // Then pop the edit box to the bounds of the cell.
  909.       var theEditPopup = document.getElementById( "service_edit_popup" );
  910.       var theEditBox = document.getElementById( "service_edit" );
  911.       var extra_x = 3; // Why do I have to give it extra?  What am I calculating wrong?
  912.       var extra_y = 8; // Why do I have to give it extra?  What am I calculating wrong?
  913.       var less_w  = 5;
  914.       var less_h  = 0;
  915.       var pos_x = extra_x + theServiceTree.boxObject.screenX + out_x.value;
  916.       var pos_y = extra_y + theServiceTree.boxObject.screenY + out_y.value;
  917.       theEditBox.setAttribute( "hidden", "false" );
  918.       theEditPopup.showPopup( theServiceTree, pos_x, pos_y, "popup" );
  919.       theEditPopup.sizeTo( out_w.value - less_w, out_h.value - less_h ); // increase the width to the size of the cell.
  920.       theEditBox.value = cell_text;
  921.       theEditBox.focus();
  922.       theEditBox.select();
  923.       isServiceEditShowing = true;
  924.     }
  925.   }
  926.   catch ( err )
  927.   {
  928.     alert( err );
  929.   }
  930. }
  931.  
  932. function onServiceEditChange( evt )
  933. {
  934.   try
  935.   {
  936.     var theServiceTree = document.getElementById( "frame_service_tree" );
  937.     if ( theServiceTree && theServiceTree.currentIndex > -1 )
  938.     {
  939.       var theEditBox = document.getElementById( "service_edit" );
  940.  
  941.       var element = theServiceTree.contentView.getItemAtIndex( theServiceTree.currentIndex );
  942.       var properties = element.getAttribute( "properties" ).split(" ");
  943.       if ( properties.length >= 5 )
  944.       {
  945.         var table = properties[ 1 ];
  946.         var guid = properties[ 2 ];
  947.         var type = properties[ 3 ];
  948.         var base_type = properties[ 4 ];
  949.         
  950.         const PlaylistManager = new Components.Constructor("@songbird.org/Songbird/PlaylistManager;1", "sbIPlaylistManager");
  951.         var aPlaylistManager = (new PlaylistManager()).QueryInterface(Components.interfaces.sbIPlaylistManager);
  952.         var aDBQuery = new sbIDatabaseQuery();
  953.         
  954.         aDBQuery.SetAsyncQuery(false);
  955.         aDBQuery.SetDatabaseGUID(guid);
  956.         
  957.         var playlist = null;
  958.         
  959.         // How do I edit a table's readable name?  I have to know what type it is?  Ugh.
  960.         switch ( base_type )
  961.         {
  962.           case "simple":  playlist = aPlaylistManager.GetSimplePlaylist(table, aDBQuery);  break;
  963.           case "dynamic": playlist = aPlaylistManager.GetDynamicPlaylist(table, aDBQuery); break;
  964.           case "smart":   playlist = aPlaylistManager.GetSmartPlaylist(table, aDBQuery);   break;
  965.           default:        playlist = aPlaylistManager.GetPlaylist(table, aDBQuery);        break;
  966.         }
  967.         
  968.         if(playlist)
  969.         {
  970.           var strReadableName = evt.target.value;
  971.           playlist.SetReadableName(strReadableName);
  972.         }
  973.       }      
  974.       HideServiceEdit();
  975.     }
  976.   }
  977.   catch ( err )
  978.   {
  979.     alert( err );
  980.   }
  981. }
  982.  
  983. function onServiceEditKeypress( evt )
  984. {
  985.   switch ( evt.keyCode )
  986.   {
  987.     case 27: // Esc
  988.       HideServiceEdit();
  989.       break;
  990.     case 13: // Return
  991.       onServiceEditChange( evt );
  992.       break;
  993.   }
  994. }
  995.  
  996. var isServiceEditShowing = false;
  997. function HideServiceEdit()
  998. {
  999.   try
  1000.   {
  1001.     if ( isServiceEditShowing )
  1002.     {
  1003.       var theEditBox = document.getElementById( "service_edit" );
  1004.       theEditBox.setAttribute( "hidden", "true" );
  1005.       var theEditPopup = document.getElementById( "service_edit_popup" );
  1006.       theEditPopup.hidePopup();
  1007.       isServiceEditShowing = false;        
  1008.     }
  1009.   }
  1010.   catch ( err )
  1011.   {
  1012.     alert( err );
  1013.   }
  1014. }
  1015.  
  1016. var theCanGoBackData = new sbIDataRemote("browser.cangoback");
  1017. var theCanGoFwdData = new sbIDataRemote("browser.cangofwd");
  1018. var theCanAddToPlaylistData = new sbIDataRemote( "browser.canplaylist" );
  1019. var theBrowserUrlData = new sbIDataRemote( "browser.url.text" );
  1020. var theBrowserImageData = new sbIDataRemote( "browser.url.image" );
  1021. var theBrowserUriData = new sbIDataRemote( "browser.uri" );
  1022. var theShowWebPlaylistData = new sbIDataRemote( "browser.playlist.show" );
  1023.  
  1024. var SBDocStartListener = {
  1025.  
  1026.   m_CurrentRequestURI: "",
  1027.   
  1028.   QueryInterface : function(aIID) {
  1029.     if (!aIID.equals(Components.interfaces.nsIWebProgressListener) &&
  1030.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  1031.         !aIID.equals(Components.interfaces.nsISupports)) 
  1032.     {
  1033.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1034.     }
  1035.     return this;
  1036.   },
  1037.  
  1038.   onStateChange : function( aWebProgress, aRequest, aState, aStatus ) 
  1039.   {
  1040.     const STATE_STOP = 0x10;
  1041.     const STATE_IS_DOCUMENT = 0x20000;
  1042.  
  1043.     try
  1044.     {
  1045.       if ( ( ( aState & ( STATE_STOP | STATE_IS_DOCUMENT ) ) != 0 ) && ( aStatus == 0x804B001E ) ) // ? 0x804B001E?
  1046.       {
  1047.         LaunchMainPaneURL( "chrome://rmp_demo/content/cannot_load.html" );
  1048.       }
  1049.     }
  1050.     catch ( err )
  1051.     {
  1052.       alert( "onStateChange - " + err );
  1053.     }
  1054.   },
  1055.   
  1056.   onStatusChange : function( aWebProgress, aRequest, aLocation ) 
  1057.   {
  1058.   },
  1059.   
  1060.   onProgressChange : function( aWebProgress, aRequest, aLocation ) 
  1061.   {
  1062.   },
  1063.   
  1064.   onSecurityChange : function( aWebProgress, aRequest, aLocation ) 
  1065.   {
  1066.   },
  1067.   
  1068.   onLocationChange : function( aWebProgress, aRequest, aLocation ) 
  1069.   {
  1070.     try
  1071.     {
  1072.       // Set the value in the text box (shown or not)
  1073.       var theMainPane = document.getElementById( "frame_main_pane" );
  1074.       var cur_uri = aLocation.asciiSpec;
  1075.       m_CurrentRequestURI = aRequest.name;
  1076. //      if ( SBGetUrlFromService( theBrowserUrlData.GetValue() ) != cur_uri )
  1077.       {
  1078.         // Set the box
  1079.         theBrowserUriData.SetValue( cur_uri );
  1080.         theBrowserUrlData.SetValue( SBGetServiceFromUrl( cur_uri ) );
  1081.         var image = SBGetServiceImageFromUrl( cur_uri );
  1082.         if ( image.length )
  1083.         {
  1084.           theBrowserImageData.SetValue( image );
  1085.         }
  1086.         
  1087.         // Set the buttons based on the session history.
  1088.         if ( theMainPane.webNavigation.sessionHistory )
  1089.         {
  1090.           // Check the buttons
  1091.           theCanGoBackData.SetValue( theMainPane.webNavigation.canGoBack );
  1092.           theCanGoFwdData.SetValue( theMainPane.webNavigation.canGoForward )
  1093.         }
  1094.         else
  1095.         {
  1096.           // Error?
  1097.         }
  1098.  
  1099. /*        
  1100.         // Hide or show the HTML box based upon whether or not the loaded page is .xul (lame heuristic)
  1101.         var theHTMLBox = document.getElementById( "frame_main_pane_html" );
  1102.         if ( theHTMLBox )
  1103.         {
  1104.           if ( cur_uri.indexOf(".xul") != -1 )
  1105.           {
  1106.             if ( SBDataGetIntValue( "option.htmlbar" ) == 0 )
  1107.             {
  1108.               theHTMLBox.setAttribute( "hidden", "true" );
  1109.             }
  1110.           }
  1111.           else
  1112.           {
  1113.             theHTMLBox.setAttribute( "hidden", "false" );
  1114.           }
  1115.         }
  1116. */        
  1117.       }
  1118.       if ( ! UrlFromServicePane )
  1119.       {
  1120.         // Clear the service tree selection (asynchronously?  is this from out of thread?)
  1121.         setTimeout( 
  1122.                     "document.getElementById( 'frame_service_tree' ).view.selection.currentIndex = -1;" +
  1123.                     "document.getElementById( 'frame_service_tree' ).view.selection.clearSelection();",
  1124.                     50 );
  1125.       }
  1126.       UrlFromServicePane = false;
  1127.       
  1128.       thePaneLoadingData.SetValue( true );
  1129.       
  1130.       // Clear the playlist tree variable so we are not confused.
  1131.       thePlaylistTree = null;
  1132.       theLibraryPlaylist = null;
  1133.       
  1134.       // Clear the tracking variable
  1135.       mainpane_listener_set = false;
  1136.       
  1137.       // Disable the "add to playlist" button until we see that there is anything to add.
  1138.       theCanAddToPlaylistData.SetValue( false );
  1139.       onBrowserPlaylistHide();
  1140.  
  1141.       // Clear the playlist tree variable so we are not confused.
  1142.       thePlaylistTree = null;
  1143.       theLibraryPlaylist = null;
  1144.       
  1145.       // Nothing in the status text
  1146.       theStatusText.SetValue( "" );
  1147.     }
  1148.     catch ( err )
  1149.     {
  1150.       alert( err );
  1151.     }
  1152.   }
  1153. }
  1154.  
  1155.  
  1156. var theCurrentURL = "";
  1157. function LaunchMainPaneURL( the_url )
  1158. {
  1159.   try
  1160.   {
  1161.     // And if it's a good string, launch it.
  1162.     if ( ( the_url ) && ( the_url.indexOf ) && ( the_url.length > 0 ) && ( theCurrentURL != the_url ) )
  1163.     {
  1164.       var theMainPane = document.getElementById( "frame_main_pane" );
  1165.       
  1166.       // Set the src attribute to load the url
  1167.       theCurrentURL = the_url;
  1168.  
  1169. //      onMainPaneTransfer();
  1170.  
  1171. /*      
  1172.       // If the last page was a xul page, replace this history entry by the new URI, so that the old chrome is actually deleted, otherwise it will keep 
  1173.       // running in the background eventho it has been unlinked from the DOM, it will generate plenty of errors since some of the functions it uses may 
  1174.       // be attached to DOM objects (ie, window.alert), and it will never be deleted, even when the application closes (ie, none of its xbl bindings 
  1175.       // destructors will be called, ever). This has the effect of excluding the playlist view (and any xul chrome) from the history altogether, ie, 
  1176.       // if you switch to a webpage, then to the library, then to a webpage again, clicking the back button on the browser will bring you back to the 
  1177.       // first webpage.
  1178.       if ( theMainPane.currentURI.spec.indexOf(".xul") != -1 )
  1179.       {
  1180.         theMainPane.loadURIWithFlags( theCurrentURL, LOAD_FLAGS_BYPASS_HISTORY, null, null );
  1181.       }
  1182.       else
  1183. */      
  1184.       {
  1185.         try
  1186.         {
  1187.           theMainPane.loadURI( theCurrentURL, null, null );
  1188.         }
  1189.         catch (e)
  1190.         {
  1191.           // Grrrr.
  1192.         }
  1193.       }
  1194.  
  1195.     }
  1196.   }
  1197.   catch ( err )
  1198.   {
  1199.     alert( err );
  1200.   }
  1201. }
  1202.  
  1203. // onBrowserBack
  1204. function onBrowserBack()
  1205. {
  1206.   // Disable the "add to playlist" button until we see that there is anything to add.
  1207.   theCanAddToPlaylistData.SetValue( false );
  1208.   onBrowserPlaylistHide();
  1209.   var theMainPane = document.getElementById( "frame_main_pane" );
  1210.   mainpane_listener_set = false;
  1211.   theMainPane.goBack();
  1212. }
  1213.  
  1214. // onBrowserFwd
  1215. function onBrowserFwd()
  1216. {
  1217.   // Disable the "add to playlist" button until we see that there is anything to add.
  1218.   theCanAddToPlaylistData.SetValue( false );
  1219.   onBrowserPlaylistHide();
  1220.   var theMainPane = document.getElementById( "frame_main_pane" );
  1221.   mainpane_listener_set = false;
  1222.   theMainPane.goForward();
  1223. }
  1224.  
  1225. // onBrowserRefresh
  1226. function onBrowserRefresh()
  1227. {
  1228.   try
  1229.   {
  1230.     var theMainPane = document.getElementById( "frame_main_pane" );
  1231.     mainpane_listener_set = false;
  1232.     theMainPane.reload();
  1233.   }
  1234.   catch( err )
  1235.   {
  1236.     alert( err );
  1237.   }
  1238. }
  1239.  
  1240. // onBrowserStop
  1241. function onBrowserStop()
  1242. {
  1243.   try
  1244.   {
  1245.     var theMainPane = document.getElementById( "frame_main_pane" );
  1246.     theMainPane.stop();
  1247.     mainpane_listener_set = false;
  1248.     onMainPaneLoad();
  1249.   }
  1250.   catch( err )
  1251.   {
  1252.     alert( err );
  1253.   }
  1254. }
  1255.  
  1256. // onBrowserHome
  1257. function onBrowserHome()
  1258. {
  1259.   LaunchMainPaneURL( "http://songbirdnest.com/player/welcome/" );
  1260. }
  1261.  
  1262. var SBWebPlaylistCommands = 
  1263. {
  1264.   m_Playlist: null,
  1265.  
  1266.   m_Ids: new Array
  1267.   (
  1268.     "library_cmd_play",
  1269. //    "library_cmd_edit",
  1270.     "library_cmd_download",
  1271.     "library_cmd_subscribe",
  1272.     "library_cmd_addtoplaylist",
  1273.     "library_cmd_addtolibrary",
  1274.     "library_cmd_burntocd",
  1275.     "library_cmd_device"
  1276.   ),
  1277.   
  1278.   m_Names: new Array
  1279.   (
  1280.     "&command.play",
  1281. //    "&command.edit",
  1282.     "&command.download",
  1283.     "&command.subscribe",
  1284.     "&command.addtoplaylist",
  1285.     "&command.addtolibrary",
  1286.     "&command.burntocd",
  1287.     "&command.device"
  1288.   ),
  1289.   
  1290.   m_Tooltips: new Array
  1291.   (
  1292.     "&command.tooltip.play",
  1293. //    "&command.tooltip.edit",
  1294.     "&command.tooltip.download",
  1295.     "&command.tooltip.subscribe",
  1296.     "&command.tooltip.addtoplaylist",
  1297.     "&command.tooltip.addtolibrary",
  1298.     "&command.tooltip.burntocd",
  1299.     "&command.tooltip.device"
  1300.   ),
  1301.  
  1302.   GetNumCommands: function()
  1303.   {
  1304.     if ( 
  1305.         ( this.m_Tooltips.length != this.m_Ids.length ) ||
  1306.         ( this.m_Names.length != this.m_Ids.length ) ||
  1307.         ( this.m_Tooltips.length != this.m_Names.length )
  1308.         )
  1309.     {
  1310.       alert( "PlaylistCommands - Array lengths do not match!" );
  1311.       return 0;
  1312.     }
  1313.     return this.m_Ids.length;
  1314.   },
  1315.  
  1316.   GetCommandId: function( index )
  1317.   {
  1318.     if ( index >= this.m_Ids.length )
  1319.     {
  1320.       return "";
  1321.     }
  1322.     return this.m_Ids[ index ];
  1323.   },
  1324.  
  1325.   GetCommandText: function( index )
  1326.   {
  1327.     if ( index >= this.m_Names.length )
  1328.     {
  1329.       return "";
  1330.     }
  1331.     return this.m_Names[ index ];
  1332.   },
  1333.  
  1334.   GetCommandToolTipText: function( index )
  1335.   {
  1336.     if ( index >= this.m_Tooltips.length )
  1337.     {
  1338.       return "";
  1339.     }
  1340.     return this.m_Tooltips[ index ];
  1341.   },
  1342.  
  1343.   GetCommandEnabled: function( index )
  1344.   {
  1345.     var retval = false;
  1346.     switch ( this.m_Ids[index] )
  1347.     {
  1348.       case "library_cmd_burntocd":
  1349.       case "library_cmd_device":
  1350.         retval = false; // not yet implemented
  1351.       break;
  1352.       default:
  1353.         retval = true;
  1354.       break;
  1355.     }
  1356.     return retval;
  1357.   },
  1358.  
  1359.   OnCommand: function( event )
  1360.   {
  1361.     if ( event.target && event.target.id )
  1362.     {
  1363.       // Was it from the toolbarbutton?
  1364.       var tbb = ( event.target.tagName == "toolbarbutton" || event.target.tagName == "xul:toolbarbutton" );
  1365.       switch( event.target.id )
  1366.       {
  1367.         case "library_cmd_play":
  1368.           if ( this.m_Playlist.tree.currentIndex != -1 )
  1369.           {
  1370.             // Repurpose the command to act as if a doubleclick
  1371.             this.m_Playlist.sendPlayEvent();
  1372.           }
  1373.         break;
  1374.         case "library_cmd_edit":
  1375.           if ( this.m_Playlist.tree.currentIndex != -1 )
  1376.           {
  1377.             if ( tbb )
  1378.             {
  1379.               // Open the editor for the whole track
  1380.             }
  1381.             else
  1382.             {
  1383.               // Edit the context cell
  1384.               this.m_Playlist.sendEditEvent();
  1385.             }
  1386.           }
  1387.         break;
  1388.         case "library_cmd_download":
  1389.         {
  1390.           try
  1391.           {        
  1392.             var filterCol = "uuid";
  1393.             var filterVals = new Array();
  1394.             
  1395.             var columnObj = this.m_Playlist.tree.columns.getNamedColumn(filterCol);
  1396.             var rangeCount = this.m_Playlist.tree.view.selection.getRangeCount();
  1397.             for (var i=0; i < rangeCount; i++) 
  1398.             {
  1399.               var start = {};
  1400.               var end = {};
  1401.               this.m_Playlist.tree.view.selection.getRangeAt( i, start, end );
  1402.               for( var c = start.value; c <= end.value; c++ )
  1403.               {
  1404.                 if (c >= this.m_Playlist.tree.view.rowCount) 
  1405.                 {
  1406. //                  alert( c + ">=" + this.m_Playlist.tree.view.rowCount );
  1407.                   continue; 
  1408.                 }
  1409.                 
  1410.                 var value = this.m_Playlist.tree.view.getCellText(c, columnObj);
  1411.                 
  1412.                 filterVals.push(value);
  1413.               }
  1414.             }
  1415.  
  1416.   /*
  1417.             for(var i in filterVals)
  1418.             {
  1419.               alert(filterVals[i]);
  1420.             }
  1421.   */
  1422.             
  1423.             onBrowserTransfer( this.m_Playlist.guid, this.m_Playlist.table, filterCol, filterVals.length, filterVals );
  1424.             // And show the download table in the chrome playlist.
  1425.             //onBrowserDownload();
  1426.           }
  1427.           catch( err )          
  1428.           {
  1429.             alert( err );
  1430.           }
  1431.         }
  1432.         break;
  1433.         case "library_cmd_subscribe":
  1434.         {
  1435.           // Bring up the subscribe dialog with the web playlist url
  1436.           var url = this.m_Playlist.type;
  1437.           var readable_name = null;
  1438.           var guid = null;
  1439.           var table = null;
  1440.           if ( url == "http" )
  1441.           {
  1442.             url = this.m_Playlist.description;
  1443.             readable_name = this.m_Playlist.readable_name;
  1444.             guid = this.m_Playlist.guid;
  1445.             table = this.m_Playlist.table;
  1446.           }
  1447.           SBSubscribe( url, guid, table, readable_name );
  1448.         }
  1449.         break;
  1450.         case "library_cmd_addtoplaylist":
  1451.         {
  1452.           this.m_Playlist.addToPlaylist();
  1453.         }
  1454.         break;
  1455.         case "library_cmd_addtolibrary":
  1456.         {
  1457.           this.m_Playlist.addToLibrary();
  1458.         }
  1459.         break;
  1460.       }
  1461.     }
  1462.   },
  1463.   
  1464.   // The object registered with the sbIPlaylistSource interface acts 
  1465.   // as a template for instances bound to specific playlist elements
  1466.   Duplicate: function()
  1467.   {
  1468.     var obj = {};
  1469.     for ( var i in this )
  1470.     {
  1471.       obj[ i ] = this[ i ];
  1472.     }
  1473.     return obj;
  1474.   },
  1475.   
  1476.   SetPlaylist: function( playlist )
  1477.   {
  1478.     this.m_Playlist = playlist;
  1479.   },
  1480.   
  1481.   QueryInterface : function(aIID)
  1482.   {
  1483.     if (!aIID.equals(Components.interfaces.sbIPlaylistCommands) &&
  1484.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  1485.         !aIID.equals(Components.interfaces.nsISupports)) 
  1486.     {
  1487.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1488.     }
  1489.     
  1490.     return this;
  1491.   }
  1492. }
  1493.  
  1494. // Register the web playlist commands at startup
  1495. if ( ( WEB_PLAYLIST_CONTEXT != "" ) && ( WEB_PLAYLIST_TABLE != "" ) )
  1496. {
  1497.   var source = new sbIPlaylistsource();
  1498.   source.RegisterPlaylistCommands( WEB_PLAYLIST_CONTEXT, WEB_PLAYLIST_TABLE, "http", SBWebPlaylistCommands );
  1499. }
  1500.  
  1501. function onBrowserPlaylist()
  1502. {
  1503.   if ( ! thePlaylistTree )
  1504.   {
  1505.     var hidden = theShowWebPlaylistData.GetIntValue() == 0;
  1506.     var show = hidden; // flip state?
  1507.     
  1508.     // And tell the playlist to point at the web table
  1509.     var ui_id = "playlist_web"
  1510.     
  1511.     if ( theWebPlaylist.ref != ( "NC:" + WEB_PLAYLIST_CONTEXT + "_" + WEB_PLAYLIST_TABLE ) )
  1512.     {
  1513.       SBWebPlaylistCommands.m_Playlist = theWebPlaylist;
  1514.       theWebPlaylist.bind( WEB_PLAYLIST_CONTEXT, WEB_PLAYLIST_TABLE, null, SBWebPlaylistCommands, SBDataGetValue( "browser.playlist.height" ), SBDataGetValue( "browser.playlist.collapsed" ) );
  1515.       show = true;
  1516.     }
  1517.     
  1518.     // Show/hide them
  1519.     theShowWebPlaylistData.SetValue( show );
  1520.   }
  1521. }
  1522.  
  1523. function onBrowserPlaylistResize()
  1524. {
  1525.   SBDataSetValue( "browser.playlist.height", theWebPlaylist.height );
  1526.   var collapsed = theWebPlaylist.previousSibling.getAttribute( "state" ) == "collapsed";
  1527.   SBDataSetValue( "browser.playlist.collapsed", collapsed );
  1528. }
  1529.  
  1530. function onBrowserDownload()
  1531. {
  1532.   if ( ! thePlaylistTree )
  1533.   {
  1534.     var hidden = theShowWebPlaylistData.GetIntValue() == 0;
  1535.     var show = hidden; // flip state?
  1536.     
  1537.     var ui_id = "playlist_web"
  1538.     var guid = theDownloadContext.GetValue();
  1539.     var table = theDownloadTable.GetValue();
  1540.     
  1541.     // Errrr, nope?
  1542.     if ( ( guid == "" ) || ( table == "" ) )
  1543.     {
  1544.       return;
  1545.     }
  1546.  
  1547.     if ( theWebPlaylist.ref != ( "NC:" + guid + "_" + table ) )
  1548.     {
  1549.       theWebPlaylist.bind( guid, table, null, SBDownloadCommands );
  1550.       show = true;
  1551.     }
  1552.     
  1553.     // Show/hide them
  1554.     theShowWebPlaylistData.SetValue( show );
  1555.   }
  1556. }
  1557. function onBrowserPlaylistHide()
  1558. {
  1559.   // Don't need this anymore
  1560.   theWebPlaylistQuery = null;
  1561.   
  1562.   // Hide the web table if it exists
  1563.   theShowWebPlaylistData.SetValue( false );
  1564.   
  1565.   // And unhook the playlist from the database
  1566.   var theTree = document.getElementById( "playlist_web" );
  1567.   if ( theTree )
  1568.   {
  1569.     var source = new sbIPlaylistsource();
  1570.     source.ClearPlaylist( theTree.ref );
  1571.     theTree.datasources = "";
  1572.     theTree.ref = "";
  1573.   }
  1574. }
  1575.  
  1576. // onHTMLUrlChange
  1577. function onHTMLUrlChange( evt )
  1578. {
  1579.   var value = evt.target.value;
  1580.   if ( value && value.length )
  1581.   {
  1582.     // Make sure the value is an url
  1583.     value = SBGetUrlFromService( value );
  1584.     // And then put it back in the box as a service
  1585.     theBrowserUriData.SetValue( value );
  1586.     theBrowserUrlData.SetValue( SBGetServiceFromUrl( value ) );
  1587.     var image = SBGetServiceImageFromUrl( value );
  1588.     if ( image.length )
  1589.     {
  1590.       theBrowserImageData.SetValue( image );
  1591.     }
  1592.     // And then go to the url.  Easy, no?
  1593.     LaunchMainPaneURL( value );
  1594.   }
  1595. }
  1596.  
  1597. function onHTMLUrlKeypress( evt )
  1598. {
  1599.   switch ( evt.keyCode )
  1600.   {
  1601.     case 13: // Enter
  1602.       evt.target.value = SBTabcompleteService( evt.target.value );
  1603.       onHTMLUrlChange( evt );
  1604.       break;
  1605.           
  1606. /*      
  1607.     case 9:  // Tab
  1608.       var value = SBTabcompleteService( evt.target.value );
  1609.       if ( value != evt.target.value )
  1610.       {
  1611.         alert ( value + " != " + evt.target.value )
  1612.         evt.target.value = value;
  1613.         onHTMLUrlChange( evt );
  1614.       }
  1615.       break;
  1616. */      
  1617.   }
  1618. }
  1619.  
  1620. var mainpane_listener_set = false;
  1621. var thePlaylistRef = new sbIDataRemote( "playlist.ref" );
  1622. var thePaneLoadingData = new sbIDataRemote( "faceplate.loading" );
  1623. thePaneLoadingData.SetValue( false );
  1624. var thePlaylistTree;
  1625.  
  1626. var theCurrentMainPaneDocument = null;
  1627. function onMainPaneLoad()
  1628. {
  1629.   try
  1630.   {
  1631.     if ( ! mainpane_listener_set )
  1632.     {
  1633.       var theMainPane = document.getElementById( "frame_main_pane" );
  1634.       if ( typeof( theMainPane ) == 'undefined' )
  1635.       {
  1636.         return;
  1637.       }
  1638.       
  1639.       //
  1640.       //
  1641.       // HORRIBLE SECURITY HACK TO GET THE PLAYLIST TREE AND INJECT FUN EVENT HANDLERS 
  1642.       //
  1643.       //
  1644.       var installed_listener = false;
  1645.       var main_iframe = theMainPane.contentDocument.getElementById( "main_iframe" );
  1646.       if ( main_iframe )
  1647.       {
  1648.         if ( main_iframe.wrappedJSObject )
  1649.           main_iframe = main_iframe.wrappedJSObject;
  1650.         // Doublecheck that the playlist piece loaded properly?
  1651.         if ( ( ! main_iframe.contentDocument ) || ( ! main_iframe.contentDocument.getElementById ) )
  1652.         {
  1653.           // Try again in 250 ms?
  1654.           setTimeout( onMainPaneLoad, 250 );
  1655.           return;
  1656.         }
  1657.         
  1658.         thePlaylistTree = main_iframe.contentDocument.getElementById( "playlist_test" );
  1659.         if ( thePlaylistTree )
  1660.         {
  1661.           // Crack the security if necessary
  1662.           if ( thePlaylistTree.wrappedJSObject )
  1663.             thePlaylistTree = thePlaylistTree.wrappedJSObject;
  1664.             
  1665.           // Wait until after the bind call?
  1666.           if ( thePlaylistTree.ref == "" )
  1667.           {
  1668.             // Try again in 250 ms?
  1669.             setTimeout( onMainPaneLoad, 250 );
  1670.             return;
  1671.           }
  1672.  
  1673.           // Drag and Drop tracker object
  1674.           thePlaylistTree.setDnDSourceTracker(sbDnDSourceTracker);
  1675.  
  1676.           // Events on the playlist object itself.            
  1677.           thePlaylistTree.addEventListener( "playlist-edit", onPlaylistEdit, true );
  1678.           thePlaylistTree.addEventListener( "playlist-play", onPlaylistPlay, true );
  1679.           thePlaylistTree.addEventListener( "command", onPlaylistContextMenu, false );  // don't force it!
  1680.             
  1681.           // Remember some values
  1682.           theLibraryPlaylist = thePlaylistTree;
  1683.           thePlaylistTree = thePlaylistTree.tree;
  1684.           thePlaylistRef.SetValue( thePlaylistTree.getAttribute( "ref" ) ); // is this set yet?
  1685.           
  1686.           // Set the current selection
  1687.           SBSyncPlaylistIndex();
  1688.           
  1689.           // And remember that we did this
  1690.           installed_listener = true;
  1691.           
  1692.           // Hide the progress bar now that we're loaded.
  1693.           thePaneLoadingData.SetValue( false );
  1694.           mainpane_listener_set = true;
  1695.         }
  1696.       }
  1697.       else
  1698.       {
  1699.         thePlaylistTree = null;
  1700.         theLibraryPlaylist = null;
  1701.       }
  1702.  
  1703.       // If we don't install a playlist listener, install an url listener.
  1704.       if ( ! installed_listener )
  1705.       {
  1706.  
  1707.         if ( theMainPane.contentDocument && theMainPane.contentDocument.getElementsByTagName('A').length == 0 )
  1708.         {
  1709.           setTimeout( onMainPaneLoad, 2500 );
  1710.           return;
  1711.         }
  1712.           
  1713.         AsyncWebDocument( theMainPane.contentDocument );
  1714.         
  1715.         // Hide the progress bar now that we're loaded.
  1716.         thePaneLoadingData.SetValue( false );
  1717.         mainpane_listener_set = true;
  1718.       }
  1719.     }
  1720.   }
  1721.   catch( err )
  1722.   {
  1723.     alert( err );
  1724.   }
  1725. }
  1726.  
  1727. function onMainPaneUnload()
  1728. {
  1729.   try
  1730.   {
  1731.   }
  1732.   catch( err )
  1733.   {
  1734.     alert( err );
  1735.   }
  1736. }
  1737.  
  1738. function IsMediaUrl( the_url )
  1739. {
  1740.   if ( ( the_url.indexOf ) && 
  1741.         (
  1742.           // Protocols at the beginning
  1743.           ( the_url.indexOf( "mms:" ) == 0 ) || 
  1744.           ( the_url.indexOf( "rtsp:" ) == 0 ) || 
  1745.           // File extensions at the end
  1746.           ( the_url.indexOf( ".pls" ) != -1 ) || 
  1747.           ( the_url.indexOf( ".m3u" ) == ( the_url.length - 4 ) ) || 
  1748. //          ( the_url.indexOf( ".rm" ) == ( the_url.length - 3 ) ) || 
  1749. //          ( the_url.indexOf( ".ram" ) == ( the_url.length - 4 ) ) || 
  1750. //          ( the_url.indexOf( ".smil" ) == ( the_url.length - 5 ) ) || 
  1751.           ( the_url.indexOf( ".mp3" ) == ( the_url.length - 4 ) ) ||
  1752.           ( the_url.indexOf( ".ogg" ) == ( the_url.length - 4 ) ) ||
  1753.           ( the_url.indexOf( ".wma" ) == ( the_url.length - 4 ) ) ||
  1754.           ( the_url.indexOf( ".wmv" ) == ( the_url.length - 4 ) ) ||
  1755.           ( the_url.indexOf( ".asx" ) == ( the_url.length - 4 ) ) ||
  1756.           ( the_url.indexOf( ".asf" ) == ( the_url.length - 4 ) ) ||
  1757.           ( the_url.indexOf( ".avi" ) == ( the_url.length - 4 ) ) ||
  1758.           ( the_url.indexOf( ".mov" ) == ( the_url.length - 4 ) ) ||
  1759.           ( the_url.indexOf( ".mp4" ) == ( the_url.length - 4 ) )
  1760.         )
  1761.       )
  1762.   {
  1763.     return true;
  1764.   }
  1765.   return false;
  1766. }
  1767.  
  1768. function IsPlaylistUrl( the_url )
  1769. {
  1770.   try
  1771.   {
  1772.     if ( the_url.indexOf )
  1773.     {
  1774.       // Make the playlist reader manager.
  1775.       const PlaylistReaderManager = new Components.Constructor("@songbird.org/Songbird/PlaylistReaderManager;1", "sbIPlaylistReaderManager");
  1776.       var aPlaylistReaderManager = (new PlaylistReaderManager()).QueryInterface(Components.interfaces.sbIPlaylistReaderManager);
  1777.       
  1778.       // Tell it what filters to be using
  1779.       var filterlist = "";
  1780.       var extensionCount = new Object;
  1781.       var extensions = aPlaylistReaderManager.SupportedFileExtensions(extensionCount);
  1782.  
  1783.       for(var i = 0; i < extensions.length; i++)
  1784.       {
  1785.         if ( the_url.indexOf( "." + extensions[i] ) != -1 )
  1786.         {      
  1787.           return true;
  1788.         }
  1789.       }
  1790.     }
  1791.   }
  1792.   catch ( err )
  1793.   {
  1794.     alert( "IsPlaylistUrl - " + err );
  1795.   }
  1796.   return false;
  1797. }
  1798.  
  1799. function GetHrefFromEvent( evt )
  1800. {
  1801.   var the_href = "";
  1802.   try
  1803.   {
  1804.     var node = evt.target;
  1805.     while ( node ) // Walk up from the event target to find the A? 
  1806.     {
  1807.       if ( node.href )
  1808.       {
  1809.         the_href = node.href;
  1810.         break;
  1811.       }
  1812.       node = node.parentNode;
  1813.     }
  1814.   }
  1815.   catch ( err )
  1816.   {
  1817.     alert( err );
  1818.   }
  1819.   return the_href;
  1820. }
  1821.  
  1822. // Catch a contextual on a media url and attempt to play it
  1823. function onLinkOver( evt )
  1824. {
  1825.   var the_url = GetHrefFromEvent( evt )
  1826.   theStatusText.SetValue( the_url );
  1827.   if ( IsMediaUrl( the_url ) )
  1828.   {
  1829.     theStatusStyle.SetValue( "font-weight: bold;" );
  1830.   }
  1831.   else
  1832.   {
  1833.     theStatusStyle.SetValue( "font-weight: normal;" );
  1834.   }
  1835. }
  1836.  
  1837. // Catch a contextual on a media url and attempt to play it
  1838. function onLinkOut( evt )
  1839. {
  1840.   theStatusText.SetValue( "" );
  1841. }
  1842.  
  1843. // Catch a contextual on a media url and attempt to play it
  1844. var theHTMLContextURL = null;
  1845. function onLinkContext( evt )
  1846. {
  1847.   try
  1848.   {
  1849.     var theMainPane = document.getElementById( "frame_main_pane" );
  1850.     var theHTMLPopup = document.getElementById( "html_context_menu" );
  1851.     theHTMLContextURL = GetHrefFromEvent( evt );
  1852.     
  1853.     var theAddItem = document.getElementById( "html.context.add" );
  1854.     var disabled = "true";
  1855.     if ( IsMediaUrl( theHTMLContextURL ) && ! SBUrlExistsInDatabase( theHTMLContextURL ) )
  1856.     {
  1857.       disabled = "false"
  1858.     }
  1859.     theAddItem.setAttribute( "disabled", disabled );
  1860.     
  1861.     theHTMLPopup.showPopup( theMainPane, theMainPane.boxObject.screenX + evt.clientX, theMainPane.boxObject.screenY + evt.clientY, "context", null, null );
  1862.   }
  1863.   catch ( err )
  1864.   {
  1865.     alert( err );
  1866.   }
  1867. }
  1868.  
  1869. // Catch a click on a media url and attempt to play it
  1870. function onMediaClick( evt )
  1871. {
  1872.   try
  1873.   {
  1874.     var the_url = GetHrefFromEvent( evt );
  1875.     if ( IsMediaUrl( the_url ) )
  1876.     {
  1877.       URL.SetValue(the_url);
  1878.       playCurrentUrl( true );
  1879.       
  1880.       evt.stopPropagation();
  1881.       evt.preventDefault();
  1882.     }
  1883.   }
  1884.   catch ( err )
  1885.   {
  1886.     alert( err );
  1887.   }
  1888. }
  1889.  
  1890. function onPlaylistKeypress( evt )
  1891. {
  1892.   switch ( evt.keyCode )
  1893.   {
  1894.     case 13: // Return
  1895.       SBPlayPlaylistIndex( thePlaylistTree.currentIndex );
  1896.       break;
  1897.   }
  1898. }
  1899.  
  1900. // Yo, play something, bitch.
  1901. function onPlaylistPlay( evt )
  1902. {
  1903.   var target = evt.target;
  1904.   if ( target.wrappedJSObject )
  1905.   {
  1906.     target = target.wrappedJSObject;
  1907.   }
  1908.   SBPlayPlaylistIndex( target.tree.currentIndex, target );
  1909. }
  1910.  
  1911. function onPlaylistDblClick( evt )
  1912. {
  1913.   if ( typeof( thePlaylistTree ) == 'undefined' )
  1914.   {
  1915.     alert( "DOM?" );
  1916.     return;
  1917.   }
  1918.   var obj = {}, row = {}, col = {}; 
  1919.   thePlaylistTree.treeBoxObject.getCellAt( evt.clientX, evt.clientY, row, col, obj );
  1920.   // If the "obj" has a value, it is a cell?
  1921.   if ( obj.value )
  1922.   {
  1923.     if ( thePlaylistTree.currentIndex != -1 )
  1924.     {
  1925.       SBPlayPlaylistIndex( thePlaylistTree.currentIndex );
  1926.     }
  1927.   }
  1928. }
  1929.  
  1930. function SBDownloadDeviceTest()
  1931. {
  1932. try
  1933. {
  1934.   aDownloadDevice = Components.classes["@songbird.org/Songbird/DownloadDevice;1"];
  1935.   if (aDownloadDevice)
  1936.   {
  1937.     aDownloadDevice = aDownloadDevice.createInstance();
  1938.     aDownloadDevice = aDownloadDevice.QueryInterface(Components.interfaces.sbIDeviceBase);
  1939.     
  1940.     if (aDownloadDevice)
  1941.     {
  1942.       listProperties( aDownloadDevice, "aDownloadDevice" );
  1943.       alert( Components.interfaces.sbIDownloadDevice );
  1944.           aDownloadDevice.name;
  1945.           aDownloadDevice.IsDownloadSupported();
  1946.           t = aDownloadDevice.DownloadTrackTable('testdb-0000','download');
  1947.     }
  1948.   }
  1949. }
  1950. catch ( err )  
  1951. {
  1952.   alert( err );
  1953. }
  1954. }
  1955.  
  1956. var theCurrentlyEditingPlaylist = null;
  1957. function onPlaylistEdit( evt )
  1958. {
  1959.   try
  1960.   {
  1961.     var playlist = evt.target;
  1962.     if ( playlist.wrappedJSObject )
  1963.       playlist = playlist.wrappedJSObject;
  1964.     
  1965.     // Make sure it's something with a uuid column.
  1966.     var filter = "uuid";
  1967.     var filter_column = playlist.tree.columns ? playlist.tree.columns[filter] : filter;
  1968.     var filter_value = playlist.tree.view.getCellText( playlist.tree.currentIndex, filter_column );
  1969.     if ( !filter_value )
  1970.     {
  1971.       return;
  1972.     }
  1973.     
  1974.     // We want to resize the edit box to the size of the cell.
  1975.     var out_x = {}, out_y = {}, out_w = {}, out_h = {}; 
  1976.     playlist.tree.treeBoxObject.getCoordsForCellItem( playlist.edit_row, playlist.edit_col, "cell",
  1977.                                                         out_x , out_y , out_w , out_h );
  1978.                            
  1979.     var cell_text = playlist.tree.view.getCellText( playlist.edit_row, playlist.edit_col );
  1980.     
  1981.     // Then pop the edit box to the bounds of the cell.
  1982.     var theMainPane = document.getElementById( "frame_main_pane" );
  1983.     var theEditPopup = document.getElementById( "playlist_edit_popup" );
  1984.     var theEditBox = document.getElementById( "playlist_edit" );
  1985.     var extra_x = 4; // Why do I have to give it extra?  What am I calculating wrong?
  1986.     var extra_y = 21; // Why do I have to give it extra?  What am I calculating wrong?
  1987.     var less_w  = 5;
  1988.     var less_h  = 0;
  1989.     var pos_x = extra_x + playlist.tree.boxObject.screenX + out_x.value;
  1990.     var pos_y = extra_y + playlist.tree.boxObject.screenY + out_y.value;
  1991.     theEditBox.setAttribute( "hidden", "false" );
  1992.     theEditPopup.showPopup( theMainPane, pos_x, pos_y, "context" );
  1993.     theEditPopup.sizeTo( out_w.value - less_w, out_h.value - less_h ); // increase the width to the size of the cell.
  1994.     theEditBox.value = cell_text;
  1995.     theEditBox.focus();
  1996.     theEditBox.select();
  1997.     isPlaylistEditShowing = true;
  1998.     theCurrentlyEditingPlaylist = playlist;
  1999.   }
  2000.   catch ( err )
  2001.   {
  2002.     alert( err );
  2003.   }
  2004. }
  2005.  
  2006. function onPlaylistEditChange( evt )
  2007. {
  2008.   try
  2009.   {
  2010.     var theEditBox = document.getElementById( "playlist_edit" );
  2011.     
  2012.     // Find the url column.
  2013.     var filter = "uuid";
  2014.     var filter_column = theCurrentlyEditingPlaylist.tree.columns ? theCurrentlyEditingPlaylist.tree.columns[filter] : filter;
  2015.     var filter_value = theCurrentlyEditingPlaylist.tree.view.getCellText( theCurrentlyEditingPlaylist.tree.currentIndex, filter_column );
  2016.     
  2017.     var the_table_column = theCurrentlyEditingPlaylist.edit_col.id;
  2018.     var the_new_value = theEditBox.value
  2019.     
  2020.     var aDBQuery = Components.classes["@songbird.org/Songbird/DatabaseQuery;1"].createInstance(Components.interfaces.sbIDatabaseQuery);
  2021.     var aMediaLibrary = Components.classes["@songbird.org/Songbird/MediaLibrary;1"].createInstance(Components.interfaces.sbIMediaLibrary);
  2022.     
  2023.     if ( ! aDBQuery || ! aMediaLibrary)
  2024.       return;
  2025.     
  2026.     aDBQuery.SetAsyncQuery(true);
  2027.     aDBQuery.SetDatabaseGUID(theCurrentlyEditingPlaylist.guid);
  2028.     aMediaLibrary.SetQueryObject(aDBQuery);
  2029.     
  2030.     aMediaLibrary.SetValueByGUID(filter_value, the_table_column, the_new_value, false);
  2031.     
  2032.     //var table = "library" // hmm... // theCurrentlyEditingPlaylist.table;
  2033.     //var q = 'update ' + table + ' set ' + the_table_column + '="' + the_new_value + '" where ' + filter + '="' + filter_value + '"';
  2034.     //aDBQuery.AddQuery( q );
  2035.     
  2036.     //var ret = aDBQuery.Execute();
  2037.     
  2038.     HidePlaylistEdit();
  2039.   }
  2040.   catch ( err )
  2041.   {
  2042.     alert( err );
  2043.   }
  2044. }
  2045.  
  2046. function onPlaylistEditKeypress( evt )
  2047. {
  2048.   switch ( evt.keyCode )
  2049.   {
  2050.     case 27: // Esc
  2051.       HidePlaylistEdit();
  2052.       break;
  2053.     case 13: // Return
  2054.       onPlaylistEditChange( evt );
  2055.       break;
  2056.   }
  2057. }
  2058.  
  2059. var isPlaylistEditShowing = false;
  2060. function HidePlaylistEdit()
  2061. {
  2062.   try
  2063.   {
  2064.     if ( isPlaylistEditShowing )
  2065.     {
  2066.       var theEditBox = document.getElementById( "playlist_edit" );
  2067.       theEditBox.setAttribute( "hidden", "true" );
  2068.       var theEditPopup = document.getElementById( "playlist_edit_popup" );
  2069.       theEditPopup.hidePopup();
  2070.       isPlaylistEditShowing = false;        
  2071.       theCurrentlyEditingPlaylist = null;
  2072.     }
  2073.   }
  2074.   catch ( err )
  2075.   {
  2076.     alert( err );
  2077.   }
  2078. }
  2079.  
  2080. // Menubar handling
  2081. function onPlaylistContextMenu( evt )
  2082. {
  2083.   try
  2084.   {
  2085.     // hacky for now
  2086.     var playlist = theLibraryPlaylist;
  2087.     if ( !playlist )
  2088.     {
  2089.       playlist = theWebPlaylist;
  2090.     }
  2091.     
  2092.     // All we do up here, now, is dispatch the search items
  2093.     onSearchTerm( playlist.context_item, playlist.context_term );
  2094.   }
  2095.   catch ( err )
  2096.   {
  2097.     alert( err );
  2098.   }
  2099. }
  2100.  
  2101. function onSearchTerm( target, in_term )
  2102. {
  2103.   var search_url = "";
  2104.   if ( in_term && in_term.length )
  2105.   {
  2106. //    var term = '"' + in_term + '"';
  2107.     var term = in_term;
  2108.     var v = target.getAttribute( "id" );
  2109.     switch ( v )
  2110.     {
  2111.       case "search.popup.songbird":
  2112.         onSearchEditIdle();
  2113.       break;
  2114.       case "search.popup.google":
  2115.         search_url = "http://www.google.com/musicsearch?q=" + term + "&sa=Search";
  2116.       break;
  2117.       case "search.popup.wiki":
  2118.         search_url = "http://en.wikipedia.org/wiki/Special:Search?search=" + term;
  2119.       break;
  2120.       case "search.popup.yahoo":
  2121.         search_url = "http://audio.search.yahoo.com/search/audio?ei=UTF-8&fr=sfp&p=" + term;
  2122.       break;
  2123.       case "search.popup.emusic":
  2124.         search_url = "http://www.emusic.com/search.html?mode=x&QT=" + term + "&x=0&y=0";
  2125.       break;
  2126.       case "search.popup.insound":
  2127.         search_url = "http://search.insound.com/search/searchmain.jsp?searchby=meta&query=" + term + "&fromindex=1&submit.x=0&submit.y=0";
  2128.       break;
  2129.       case "search.popup.odeo":
  2130.         search_url = "http://odeo.com/search/query/?q=" + term + "&Search.x=0&Search.y=0";
  2131.       break;
  2132.       case "search.popup.shoutcast":
  2133.         search_url = "http://www.shoutcast.com/directory/?s=" + term;
  2134.       break;
  2135.       case "search.popup.radiotime":
  2136.         search_url = "http://radiotime.com/toppicks.aspx?p=0&st=0&t=" + term;
  2137.       break;
  2138.       case "lyrics.popup.google":
  2139.         search_url = "http://www.google.com/search?q=lyrics " + term + "&sa=Search&client=pub-4053348708517670&forid=1&ie=ISO-8859-1&oe=ISO-8859-1&hl=en&GALT:#333333;GL:1;DIV:#37352E;VLC:000000;AH:center;BGC:C6B396;LBGC:8E866F;ALC:000000;LC:000000;T:44423A;GFNT:663333;GIMP:663333;FORID:1;";
  2140.       break;
  2141.     }
  2142.   }
  2143.   if ( search_url.length )
  2144.   {
  2145.     LaunchMainPaneURL( search_url );
  2146.   }
  2147. }
  2148.  
  2149. var repeat = new sbIDataRemote( "playlist.repeat" ); 
  2150.  
  2151. // Menubar handling
  2152. function onMenu( target )
  2153. {
  2154.   var v = target.getAttribute( "id" );
  2155.   switch ( v )
  2156.   {
  2157.     case "file.new":
  2158.       SBNewPlaylist();
  2159.     break;
  2160.     case "file.smart":
  2161.       SBNewSmartPlaylist();
  2162.     break;
  2163.     case "file.remote":
  2164.       SBSubscribe( "", "", "", "" );
  2165.     break;
  2166.     case "file.file":
  2167.       SBFileOpen();
  2168.     break;
  2169.     case "file.url":
  2170.       SBUrlOpen();
  2171.     break;
  2172.     case "file.mab":
  2173.       SBMabOpen();
  2174.     break;
  2175.     case "file.playlist":
  2176.       SBPlaylistOpen();
  2177.     break;
  2178.     case "file.scan":
  2179.       SBScanMedia();
  2180.     break;
  2181.     case "file.dlfolder":
  2182.       SBSetDownloadFolder();
  2183.     break;
  2184.     case "file.watch":
  2185.       SBWatchFolders();
  2186.     break;
  2187. /*    
  2188.     case "file.htmlbar":
  2189.       if ( SBDataGetIntValue( "option.htmlbar" ) == 0 )
  2190.       {
  2191.         SBDataSetValue( "option.htmlbar", 1 );
  2192.       }
  2193.       else
  2194.       {
  2195.         SBDataSetValue( "option.htmlbar", 0 );
  2196.       }
  2197.     break;
  2198. */    
  2199.     case "file.skin":
  2200. try    
  2201. {
  2202.       var root = "window." + document.documentElement.id;
  2203.       SBDataSetValue( root + ".x", document.documentElement.boxObject.screenX );
  2204.       SBDataSetValue( root + ".y", document.documentElement.boxObject.screenY );
  2205.       SBDataSetValue( root + ".w", document.documentElement.boxObject.width );
  2206.       SBDataSetValue( root + ".h", document.documentElement.boxObject.height );
  2207.       var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  2208.       if ( SBDataGetIntValue( "option.skin" ) == 0 )
  2209.       {
  2210.         onMinimize();
  2211.         SBDataSetValue( "option.skin", 1 );
  2212.         prefs.setCharPref("general.skins.selectedSkin", "otherskin");  
  2213.         window.open( "chrome://rmp_demo/content/mainwin.xul", "", "chrome,modal=no" );
  2214.         setTimeout( "onExit();", 1000 );
  2215.       }
  2216.       else
  2217.       {
  2218.         onMinimize();
  2219.         SBDataSetValue( "option.skin", 0 );
  2220.         prefs.setCharPref("general.skins.selectedSkin", "songbird");  
  2221.         window.open( "chrome://rmp_demo/content/mainwin.xul", "", "chrome,modal=no" );
  2222.         setTimeout( "onExit();", 1000 );
  2223.       }
  2224. }
  2225. catch ( err )      
  2226. {
  2227.   alert( err );
  2228. }
  2229.     break;
  2230.     case "file.window":
  2231.       SBMiniplayerOpen();
  2232.     break;
  2233.     case "file.koshi":
  2234.       SBKoshiOpen();
  2235.     break;
  2236.     case "file.about":
  2237.       About(); 
  2238.     break;
  2239.     case "file.exit":
  2240.       quitApp();
  2241.     break;
  2242.     case "control.play":
  2243.       if ( ! myPlayerRemote.isPlaying() )
  2244.       {
  2245.         onPlay();
  2246.       }
  2247.       else
  2248.       {
  2249.         onPause();
  2250.       }
  2251.     break;
  2252.     case "control.next":
  2253.       onFwd();
  2254.     break;
  2255.     case "control.prev":
  2256.       onBack();
  2257.     break;
  2258.     case "control.shuf":
  2259.       onShuffle();
  2260.     break;
  2261.     case "control.repa":
  2262.       repeat.SetValue( 2 );
  2263.     break;
  2264.     case "control.rep1":
  2265.       repeat.SetValue( 1 );
  2266.     break;
  2267.     case "control.repx":
  2268.       repeat.SetValue( 0 );
  2269.     break;
  2270.     case "menu.extensions":
  2271.       SBExtensionsManagerOpen();
  2272.     break;
  2273. /*    case "menu.dominspector":
  2274.       SBDOMInspectorOpen();
  2275.     break;*/
  2276.     
  2277.     default:
  2278.       if ( target.value )
  2279.       {
  2280.         LaunchMainPaneURL( target.value );
  2281.       }
  2282.     break;
  2283.   }
  2284. }
  2285.  
  2286. function SBSetDownloadFolder()
  2287. {
  2288.   // Just open the window, we don't care what the user does in it.
  2289.   SBOpenModalDialog( "chrome://rmp_demo/content/download.xul", "", "chrome,modal=yes,centerscreen", null );
  2290. }
  2291.  
  2292. function SBWatchFolders()
  2293. {
  2294.   SBOpenModalDialog( "chrome://rmp_demo/content/watch_folders.xul", "", "chrome,modal=yes,centerscreen", null );
  2295. }
  2296.  
  2297. // Menubar handling
  2298. function onHTMLContextMenu( target )
  2299. {
  2300.   if ( theHTMLContextURL )
  2301.   {
  2302.     var v = target.getAttribute( "id" );
  2303.     switch ( v )
  2304.     {
  2305.       case "html.context.open":
  2306.         if ( IsMediaUrl( theHTMLContextURL ) )
  2307.         {
  2308.           URL.SetValue(theHTMLContextURL);
  2309.           playCurrentUrl( true );
  2310.         }
  2311.         else
  2312.         {
  2313.           LaunchMainPaneURL( theHTMLContextURL );
  2314.         }
  2315.       break;
  2316.       case "html.context.play":
  2317.         URL.SetValue(theHTMLContextURL);
  2318.         playCurrentUrl( true );
  2319.       break;
  2320.       case "html.context.add":
  2321.         SBAddUrlToDatabase( theHTMLContextURL );
  2322.       break;
  2323.       case "html.context.playlist":
  2324.         SBScanServiceTreeNewEntryEditable();
  2325.         var success = thePlaylistReader.AutoLoad(theHTMLContextURL, "songbird", ConvertUrlToDisplayName( theHTMLContextURL ), "http", theHTMLContextURL, "", null);
  2326.         SBScanServiceTreeNewEntryStart();
  2327.       break;
  2328.     }
  2329.     theHTMLContextURL = null; // clear it because now we're done.
  2330.   }
  2331. }
  2332.  
  2333.  
  2334. var theMediaScanIsOpen = new sbIDataRemote( "media_scan.open" );
  2335. function SBScanMedia( )
  2336. {
  2337.   theMediaScanIsOpen.SetValue( true );
  2338.   const nsIFilePicker = Components.interfaces.nsIFilePicker;
  2339.   const CONTRACTID_FILE_PICKER = "@mozilla.org/filepicker;1";
  2340.   var fp = Components.classes[CONTRACTID_FILE_PICKER].createInstance(nsIFilePicker);
  2341.   var welcome = "Welcome";
  2342.   var scan = "Scan";
  2343.   try
  2344.   {
  2345.     welcome = theSongbirdStrings.getString("faceplate.welcome");
  2346.     scan = theSongbirdStrings.getString("faceplate.scan");
  2347.   } catch(e) {}
  2348.   fp.init( window, welcome + "!\n\n" + scan, nsIFilePicker.modeGetFolder );
  2349.   var res = fp.show();
  2350.   if ( res == nsIFilePicker.returnOK )
  2351.   {
  2352.     var media_scan_data = new Object();
  2353.     media_scan_data.URL = fp.file.path;
  2354.     media_scan_data.retval = "";
  2355.     // Open the non-modal dialog
  2356.     SBOpenModalDialog( "chrome://rmp_demo/content/media_scan.xul", "media_scan", "chrome,modal=yes,centerscreen", media_scan_data );
  2357.   }
  2358.   theMediaScanIsOpen.SetValue( false  );
  2359. }
  2360.  
  2361. function SBMabOpen()
  2362. {
  2363.   var mab_data = new Object();
  2364.   mab_data.retval = "";
  2365.   
  2366.   // Open the modal dialog
  2367.   SBOpenModalDialog( "chrome://rmp_demo/content/mab.xul", "Mozilla Amazon Browser", "chrome,modal=no", mab_data );
  2368. }
  2369.  
  2370. function SBNewPlaylist()
  2371. {
  2372.   try
  2373.   {
  2374.     SBScanServiceTreeNewEntryEditable();
  2375.     var query = new sbIDatabaseQuery();
  2376.     query.SetDatabaseGUID( "songbird" );
  2377.     var playlistmanager = new sbIPlaylistManager();
  2378.     var aUUIDGenerator = Components.classes["@mozilla.org/uuid-generator;1"].createInstance(Components.interfaces.nsIUUIDGenerator);
  2379.     var playlistguid = aUUIDGenerator.generateUUID();
  2380.     var playlist = playlistmanager.CreatePlaylist( playlistguid, name, "Playlist", "user", query );
  2381.     SBScanServiceTreeNewEntryStart();
  2382.   }
  2383.   catch ( err )
  2384.   {
  2385.     alert( "SBNewPlaylist - " + err );
  2386.   }
  2387. }
  2388.  
  2389. function SBMiniplayerOpen()
  2390. {
  2391.   // Open the window
  2392.   window.open( "chrome://rmp_demo/content/miniplayer/miniplayer.xul", "", "chrome,modal=no,popup=yes" );
  2393.   onExit();
  2394. }
  2395.  
  2396. function SBNewSmartPlaylist( guid, table )
  2397. {
  2398.   SBScanServiceTreeNewEntryEditable(); // Do this right before you add to the servicelist?
  2399.   
  2400.   // Make a magic data object to get passed to the dialog
  2401.   var smart_playlist = new Object();
  2402.   smart_playlist.retval = "";
  2403.   smart_playlist.guid = guid;
  2404.   smart_playlist.table = table
  2405.   // Open the window
  2406.   SBOpenModalDialog( "chrome://rmp_demo/content/smart_playlist.xul", "", "chrome,modal=yes,centerscreen", smart_playlist );
  2407.   
  2408.   if ( smart_playlist.retval == "ok" )
  2409.   {
  2410.     SBScanServiceTreeNewEntryStart(); // And this once you know you really did?
  2411.   }
  2412. }
  2413.  
  2414. function SBKoshiOpen()
  2415. {
  2416.   // Make a magic data object to get passed to the dialog
  2417.   var koshi_data = new Object();
  2418.   koshi_data.retval = "";
  2419.   // Open the window
  2420.   SBOpenModalDialog( "chrome://rmp_demo/content/koshi_test.xul", "", "chrome,modal=yes,centerscreen", koshi_data );
  2421. }
  2422.  
  2423. function SBExtensionsManagerOpen()
  2424. {
  2425.   const EMTYPE = "Extension:Manager";
  2426.   
  2427.   var aOpenMode = 'extensions';
  2428.  
  2429.   var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  2430.                      .getService(Components.interfaces.nsIWindowMediator);
  2431.   var needToOpen = true;
  2432.   var windowType = EMTYPE + "-" + aOpenMode;
  2433.   var windows = wm.getEnumerator(windowType);
  2434.   while (windows.hasMoreElements()) {
  2435.     var theEM = windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindowInternal);
  2436.     if (theEM.document.documentElement.getAttribute("windowtype") == windowType) {
  2437.       theEM.focus();
  2438.       needToOpen = false;
  2439.       break;
  2440.     }
  2441.   }
  2442.  
  2443.   if (needToOpen) {
  2444.     const EMURL = "chrome://mozapps/content/extensions/extensions.xul?type=" + aOpenMode;
  2445.     const EMFEATURES = "chrome,dialog=no,resizable";
  2446.     window.openDialog(EMURL, "", EMFEATURES);
  2447.   }
  2448. }
  2449.  
  2450. function SBDOMInspectorOpen()
  2451. {
  2452.   window.open("chrome://inspector/content/", "", "chrome,dialog=no,resizable");
  2453. }
  2454.  
  2455. function SBSubscribe( url, guid, table, readable_name )
  2456. {
  2457.   // Make a magic data object to get passed to the dialog
  2458.   var subscribe_data = new Object();
  2459.   subscribe_data.retval = "";
  2460.   subscribe_data.url = url;
  2461.   subscribe_data.readable_name = readable_name;
  2462.   // Open the window
  2463.   SBScanServiceTreeNewEntryEditable();
  2464.   SBOpenModalDialog( "chrome://rmp_demo/content/subscribe.xul", "", "chrome,modal=yes,centerscreen", subscribe_data );
  2465.   if ( subscribe_data.retval == "ok" )
  2466.   {
  2467.     if ( guid && table )
  2468.     {
  2469.       const PlaylistManager = new Components.Constructor("@songbird.org/Songbird/PlaylistManager;1", "sbIPlaylistManager");
  2470.       var aPlaylistManager = new PlaylistManager();
  2471.       aPlaylistManager = aPlaylistManager.QueryInterface(Components.interfaces.sbIPlaylistManager);
  2472.       var aDBQuery = new sbIDatabaseQuery();
  2473.       aDBQuery.SetAsyncQuery(false);
  2474.       aDBQuery.SetDatabaseGUID(guid);
  2475.       aPlaylistManager.DeletePlaylist( table, aDBQuery );
  2476.     }
  2477.  
  2478.     SBScanServiceTreeNewEntryStart();
  2479.   }
  2480. }
  2481.  
  2482. function About( )
  2483. {
  2484.   // Make a magic data object to get passed to the dialog
  2485.   var about_data = new Object();
  2486.   about_data.retval = "";
  2487.   // Open the modal dialog
  2488.   SBOpenModalDialog( "chrome://rmp_demo/content/about.xul", "about", "chrome,modal=yes,centerscreen", about_data );
  2489.   if ( about_data.retval == "ok" )
  2490.   {
  2491.   }  
  2492. }
  2493.  
  2494. // Debugging Tool
  2495. function listProperties(obj, objName) 
  2496. {
  2497.     var columns = 3;
  2498.     var count = 0;
  2499.     var result = "";
  2500.     for (var i in obj) 
  2501.     {
  2502.         result += objName + "." + i + " = " + obj[i] + "\t\t\t";
  2503.         count = ++count % columns;
  2504.         if ( count == columns - 1 )
  2505.         {
  2506.           result += "\n";
  2507.         }
  2508.     }
  2509.     alert(result);
  2510. }
  2511.  
  2512. var SBDropObserver = 
  2513. {
  2514.   getSupportedFlavours : function () 
  2515.   {
  2516.     var flavours = new FlavourSet();
  2517.     flavours.appendFlavour("application/x-moz-file","nsIFile");
  2518. //    flavours.appendFlavour("application/x-moz-url");
  2519.     return flavours;
  2520.   },
  2521.   onDragOver: function ( evt, flavour, session )
  2522.   {
  2523.   },
  2524.   onDrop: function ( evt, dropdata, session )
  2525.   {
  2526.     if ( dropdata.data != "" )
  2527.     {
  2528.       // if it has a path property
  2529.       if ( dropdata.data.path )
  2530.       {
  2531.         theDropPath = dropdata.data.path;
  2532.         theDropIsDir = dropdata.data.isDirectory();
  2533.         setTimeout( SBDropped, 10 ); // Next frame
  2534.         
  2535.       }
  2536.     }
  2537.   }
  2538. };
  2539.  
  2540. var theDropPath = "";
  2541. var theDropIsDir = false;
  2542. function SBDropped()
  2543. {
  2544.   if ( IsMediaUrl( theDropPath ) )
  2545.   {
  2546.     // try to add it to the database.
  2547.     SBAddUrlToDatabase( theDropPath );
  2548.     // and then play it.
  2549.     URL.SetValue(theDropPath);
  2550.     playCurrentUrl( true );
  2551.   }
  2552.   else if ( theDropIsDir )
  2553.   {
  2554.     theMediaScanIsOpen.SetValue( true );
  2555.     // otherwise, fire off the media scan page.
  2556.     var media_scan_data = new Object();
  2557.     media_scan_data.URL = theDropPath;
  2558.     media_scan_data.retval = "";
  2559.     // Open the non-modal dialog
  2560.     SBOpenModalDialog( "chrome://rmp_demo/content/media_scan.xul", "media_scan", "chrome,modal=yes,centerscreen", media_scan_data );
  2561.     theMediaScanIsOpen.SetValue( false  );
  2562.   }
  2563. }
  2564.  
  2565. function SBGetServiceFromUrl( url )
  2566. {
  2567.   retval = url;
  2568.   try
  2569.   {
  2570.     var theServiceTree = document.getElementById( "frame_service_tree" );
  2571.     if ( theServiceTree )
  2572.     {
  2573.       // Find the columns. 
  2574.       var urlcolumn = theServiceTree.columns ? theServiceTree.columns["url"] : "url";
  2575.       var labelcolumn = theServiceTree.columns ? theServiceTree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  2576.       
  2577.       for ( var i = 0; i < theServiceTree.view.rowCount; i++ )
  2578.       {
  2579.         // Get the text of the hidden tree cell, this contains the url.
  2580.         var tree_url = theServiceTree.view.getCellText( i, urlcolumn );
  2581.         var tree_label = theServiceTree.view.getCellText( i, labelcolumn );
  2582.         
  2583.         if ( tree_url == url )
  2584.         {
  2585.           retval = tree_label;
  2586.           break;
  2587.         }
  2588.       }
  2589.     }
  2590.   }
  2591.   catch ( err )
  2592.   {
  2593.     alert( "SBGetServiceFromUrl - " + err )
  2594.   }
  2595.   return retval;
  2596. }
  2597.  
  2598. function SBGetServiceImageFromUrl( url )
  2599. {
  2600.   retval = "";
  2601.   try
  2602.   {
  2603.     var theServiceTree = document.getElementById( "frame_service_tree" );
  2604.     if ( theServiceTree )
  2605.     {
  2606.       // Find the columns. 
  2607.       var urlcolumn = theServiceTree.columns ? theServiceTree.columns["url"] : "url";
  2608.       var labelcolumn = theServiceTree.columns ? theServiceTree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  2609.       
  2610.       for ( var i = 0; i < theServiceTree.view.rowCount; i++ )
  2611.       {
  2612.         // Get the text of the hidden tree cell, this contains the url.
  2613.         var tree_url = theServiceTree.view.getCellText( i, urlcolumn );
  2614.         var tree_image = theServiceTree.view.getImageSrc( i, labelcolumn );
  2615.         
  2616.         if ( tree_url == url )
  2617.         {
  2618.           retval = tree_image;
  2619.           break;
  2620.         }
  2621.       }
  2622.     }
  2623.   }
  2624.   catch ( err )
  2625.   {
  2626.     alert( "SBGetServiceImageFromUrl - " + err )
  2627.   }
  2628.   return retval;
  2629. }
  2630.  
  2631. function SBGetUrlFromService( service )
  2632. {
  2633.   retval = service;
  2634.   try
  2635.   {
  2636.     var theServiceTree = document.getElementById( "frame_service_tree" );
  2637.     if ( theServiceTree )
  2638.     {
  2639.       // Find the columns. 
  2640.       var urlcolumn = theServiceTree.columns ? theServiceTree.columns["url"] : "url";
  2641.       var labelcolumn = theServiceTree.columns ? theServiceTree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  2642.       
  2643.       for ( var i = 0; i < theServiceTree.view.rowCount; i++ )
  2644.       {
  2645.         // Get the text of the hidden tree cell, this contains the url.
  2646.         var tree_url = theServiceTree.view.getCellText( i, urlcolumn );
  2647.         var tree_label = theServiceTree.view.getCellText( i, labelcolumn );
  2648.         
  2649.         if ( tree_label == service )
  2650.         {
  2651.           retval = tree_url;
  2652.           break;
  2653.         }
  2654.       }
  2655.     }
  2656.   }
  2657.   catch ( err )
  2658.   {
  2659.     alert( "SBGetUrlFromService - " + err )
  2660.   }
  2661.   return retval;
  2662. }
  2663.  
  2664. function SBTabcompleteService( service )
  2665. {
  2666.   retval = service;
  2667.   var service_lc = service.toLowerCase();
  2668.   try
  2669.   {
  2670.     var theServiceTree = document.getElementById( "frame_service_tree" );
  2671.     if ( theServiceTree )
  2672.     {
  2673.       // Find the columns. 
  2674.       var urlcolumn = theServiceTree.columns ? theServiceTree.columns["url"] : "url";
  2675.       var labelcolumn = theServiceTree.columns ? theServiceTree.columns["frame_service_tree_label"] : "frame_service_tree_label";
  2676.  
  2677.       var found_one = false;      
  2678.       for ( var i = 0; i < theServiceTree.view.rowCount; i++ )
  2679.       {
  2680.         // Get the text of the hidden tree cell, this contains the url.
  2681.         var tree_label = theServiceTree.view.getCellText( i, labelcolumn );
  2682.         
  2683.         var label_lc = tree_label.toLowerCase();
  2684.         
  2685.         // If we are the beginning of the label string
  2686.         if ( label_lc.indexOf( service_lc ) == 0 )
  2687.         {
  2688.           if ( found_one )
  2689.           {
  2690.             retval = service; // only find ONE!
  2691.             break;
  2692.           }
  2693.           else
  2694.           {
  2695.             found_one = true; // only find ONE!
  2696.             retval = tree_label;
  2697.           }
  2698.         }
  2699.       }
  2700.     }
  2701.   }
  2702.   catch ( err )
  2703.   {
  2704.     alert( "SBTabcompleteService - " + err )
  2705.   }
  2706.   return retval;
  2707. }
  2708.  
  2709.  
  2710. // Assume there's just one?
  2711. var theDownloadContext = new sbIDataRemote( "download.context" );
  2712. var theDownloadTable = new sbIDataRemote( "download.table" );
  2713. var theDownloadExists = new sbIDataRemote( "browser.hasdownload" );
  2714.  
  2715. /*
  2716. var theDownloadListener = 
  2717. {
  2718.   m_queryObj: null,
  2719.   m_libraryObj: null,
  2720.   
  2721.   CreateQueryObj: function()
  2722.   {
  2723.     this.m_queryObj = new sbIDatabaseQuery();
  2724.     this.m_queryObj.SetAsyncQuery(true);
  2725.     this.m_queryObj.SetDatabaseGUID("songbird");
  2726.   },
  2727.  
  2728.   CreateLibraryObj: function()
  2729.   {
  2730.     if(this.m_libraryObj == null)
  2731.     {
  2732.       const MediaLibrary = new Components.Constructor("@songbird.org/Songbird/MediaLibrary;1", "sbIMediaLibrary");
  2733.       this.m_libraryObj = (new MediaLibrary()).QueryInterface(Components.interfaces.sbIMediaLibrary);
  2734.     
  2735.       if(this.m_queryObj == null)
  2736.           this.CreateQueryObj();
  2737.         
  2738.       this.m_libraryObj.SetQueryObject(this.m_queryObj);
  2739.     }
  2740.   },
  2741.   
  2742.   QueryInterface : function(aIID) 
  2743.   {
  2744.     if (!aIID.equals(Components.interfaces.sbIDeviceBaseCallback) &&
  2745.         !aIID.equals(Components.interfaces.nsISupports)) 
  2746.     {
  2747.       throw Components.results.NS_ERROR_NO_INTERFACE;
  2748.     }
  2749.     return this;
  2750.   },
  2751.   
  2752.   onTransferStart: function(sourceURL, destinationURL)
  2753.   {
  2754.   },
  2755.   
  2756.   onTransferComplete: function(sourceURL, destinationURL, transferStatus)
  2757.   {
  2758.     if(transferStatus == 1)
  2759.     {
  2760.       this.CreateLibraryObj(); 
  2761.       
  2762.       var aKeys = ["title"];
  2763.       var aValues = [];
  2764.       
  2765.       var aLocalFile = (Components.classes["@mozilla.org/file/local;1"]).createInstance(Components.interfaces.nsILocalFile);
  2766.       aLocalFile.initWithPath(destinationURL);
  2767.     
  2768.       aValues.push(aLocalFile.leafName);
  2769.       this.m_libraryObj.AddMedia(destinationURL, aKeys.length, aKeys, aValues.length, aValues, false, false);
  2770.     }
  2771.   }
  2772. };
  2773. */
  2774.  
  2775. function onBrowserTransfer(guid, table, strFilterColumn, nFilterValueCount, aFilterValues)
  2776. {
  2777.     try
  2778.     {
  2779.         theWebPlaylistQuery = null; 
  2780.           
  2781.         aDeviceManager = Components.classes["@songbird.org/Songbird/DeviceManager;1"].createInstance(Components.interfaces.sbIDeviceManager);
  2782.         if (aDeviceManager)
  2783.         {
  2784.             aDownloadDevice = aDeviceManager.GetDevice('Songbird Download Device');
  2785.             if (aDownloadDevice)
  2786.             {
  2787.                 // Make a magic data object to get passed to the dialog
  2788.                 var download_data = new Object();
  2789.                 download_data.retval = "";
  2790.                 download_data.value = SBDataGetValue( "download.folder" );
  2791.                 
  2792.                 if ( ( SBDataGetIntValue( "download.always" ) == 1 ) && ( download_data.value.length > 0 ) )
  2793.                 {
  2794.                   download_data.retval = "ok";
  2795.                 }
  2796.                 else
  2797.                 {
  2798.                   // Open the window
  2799.                   SBOpenModalDialog( "chrome://rmp_demo/content/download.xul", "", "chrome,modal=yes,centerscreen", download_data );
  2800.                 }
  2801.  
  2802.                 // Pick download destination
  2803.                 if ( ( download_data.retval == "ok" ) && ( download_data.value.length > 0 ) )
  2804.                 {
  2805.                   var downloadTable = {};
  2806.                   // Passing empty string for device name as download device has just one device
  2807.                   // Prepare table for download & get the name for newly prepared download table
  2808.                   //aDownloadDevice.AddCallback(theDownloadListener);
  2809.                   
  2810.                   aDownloadDevice.AutoDownloadTable('', guid, table, strFilterColumn, nFilterValueCount, aFilterValues, '', download_data.value, downloadTable);
  2811.                   
  2812.                   // Record the current download table
  2813.                   theDownloadContext.SetValue( aDownloadDevice.GetContext('') )
  2814.                   theDownloadTable.SetValue( downloadTable.value );
  2815.                   theDownloadExists.SetValue( true );
  2816.                   
  2817.                   // Register the guid and table with the playlist source to always show special download commands.
  2818.                   SBDownloadCommands.m_Device = aDownloadDevice;
  2819.                   var source = new sbIPlaylistsource();
  2820.                   source.RegisterPlaylistCommands( aDownloadDevice.GetContext(''), downloadTable.value, "download", SBDownloadCommands );
  2821.                 }
  2822.             }
  2823.         }
  2824.     }
  2825.     
  2826.     catch ( err )
  2827.     {
  2828.         alert( err );
  2829.     }
  2830. }
  2831.  
  2832. var SBDownloadCommands = 
  2833. {
  2834.   DEVICE_IDLE :               0,
  2835.   DEVICE_BUSY :               1,
  2836.   DEVICE_DOWNLOADING :        2,
  2837.   DEVICE_UPLOADING :          3,
  2838.   DEVICE_DOWNLOAD_PAUSED :    4,
  2839.   DEVICE_UPLOAD_PAUSED :      5,
  2840.   DEVICE_DELETING :           6,
  2841.   
  2842.   m_Playlist: null,
  2843.   m_Device: null,
  2844.  
  2845.   m_Ids: new Array
  2846.   (
  2847.     "library_cmd_play",
  2848.     "library_cmd_remove",
  2849.     "library_cmd_pause"
  2850.   ),
  2851.   
  2852.   m_Names: new Array
  2853.   (
  2854.     "&command.play",
  2855.     "&command.remove",
  2856.     "&command.pause"
  2857.   ),
  2858.   
  2859.   m_Tooltips: new Array
  2860.   (
  2861.     "&command.tooltip.play",
  2862.     "&command.tooltip.remove",
  2863.     "&command.tooltip.pause"
  2864.   ),
  2865.  
  2866.   GetNumCommands: function()
  2867.   {
  2868.     if ( 
  2869.         ( this.m_Tooltips.length != this.m_Ids.length ) ||
  2870.         ( this.m_Names.length != this.m_Ids.length ) ||
  2871.         ( this.m_Tooltips.length != this.m_Names.length )
  2872.        )
  2873.     {
  2874.       alert( "PlaylistCommands - Array lengths do not match!" );
  2875.       return 0;
  2876.     }
  2877.     return this.m_Ids.length;
  2878.   },
  2879.  
  2880.   GetCommandId: function( index )
  2881.   {
  2882.     if ( index == 2 )
  2883.     {
  2884.       if ( this.m_Device )
  2885.       {
  2886.         if ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOAD_PAUSED )
  2887.         {
  2888.           this.m_Ids[ index ] = "library_cmd_resume";
  2889.         }
  2890.         else
  2891.         {
  2892.           this.m_Ids[ index ] = "library_cmd_pause";
  2893.         }
  2894.       }
  2895.     }
  2896.     if ( index >= this.m_Ids.length )
  2897.     {
  2898.       return "";
  2899.     }
  2900.     return this.m_Ids[ index ];
  2901.   },
  2902.  
  2903.   GetCommandText: function( index )
  2904.   {
  2905.     if ( index == 2 )
  2906.     {
  2907.       if ( this.m_Device )
  2908.       {
  2909.         if ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOAD_PAUSED )
  2910.         {
  2911.           this.m_Names[ index ] = "&command.resume";
  2912.         }
  2913.         else
  2914.         {
  2915.           this.m_Names[ index ] = "&command.pause";
  2916.         }
  2917.       }
  2918.     }
  2919.     if ( index >= this.m_Names.length )
  2920.     {
  2921.       return "";
  2922.     }
  2923.     return this.m_Names[ index ];
  2924.   },
  2925.  
  2926.   GetCommandToolTipText: function( index )
  2927.   {
  2928.     if ( index == 2 )
  2929.     {
  2930.       if ( this.m_Device )
  2931.       {
  2932.         if ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOAD_PAUSED )
  2933.         {
  2934.           this.m_Tooltips[ index ] = "&command.tooltip.resume";
  2935.         }
  2936.         else
  2937.         {
  2938.           this.m_Tooltips[ index ] = "&command.tooltip.pause";
  2939.         }
  2940.       }
  2941.     }
  2942.     if ( index >= this.m_Tooltips.length )
  2943.     {
  2944.       return "";
  2945.     }
  2946.     return this.m_Tooltips[ index ];
  2947.   },
  2948.  
  2949.   GetCommandEnabled: function( index )
  2950.   {
  2951.     var retval = false;
  2952.     if ( this.m_Device )
  2953.     {
  2954.       switch( index )
  2955.       {
  2956.         case 0:
  2957.         case 1:
  2958.           retval = true;
  2959.         break;
  2960.         case 2:
  2961.           retval = ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOADING ) || ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOAD_PAUSED )
  2962.         break;
  2963.       }
  2964.     }
  2965.     return retval;
  2966.   },
  2967.  
  2968.   OnCommand: function( event )
  2969.   {
  2970.     if ( this.m_Device && event.target && event.target.id )
  2971.     {
  2972.       // Was it from the toolbarbutton?
  2973.       var tbb = ( event.target.tagName == "toolbarbutton" || event.target.tagName == "xul:toolbarbutton" );
  2974.       switch( event.target.id )
  2975.       {
  2976.         case "library_cmd_play":
  2977.           if ( this.m_Playlist.tree.currentIndex != -1 )
  2978.           {
  2979.             // Repurpose the command to act as if a doubleclick
  2980.             this.m_Playlist.sendPlayEvent();
  2981.           }
  2982.         break;
  2983.         case "library_cmd_remove":
  2984.           if ( this.m_Playlist.tree.currentIndex != -1 )
  2985.           {
  2986.             // remove the currently select tracks
  2987.             this.m_Playlist.removeTracks();
  2988.           }
  2989.         break;
  2990.         case "library_cmd_pause":
  2991.         case "library_cmd_resume":
  2992.           if ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOADING )
  2993.           {
  2994.             this.m_Device.SuspendTransfer('');
  2995.           }
  2996.           else if ( this.m_Device.GetDeviceState('') == this.DEVICE_DOWNLOAD_PAUSED )
  2997.           {
  2998.             this.m_Device.ResumeTransfer('');
  2999.           }
  3000.           // Since we changed state, update the command buttons.
  3001.           this.m_Playlist.refreshCommands();
  3002.         break;
  3003.       }
  3004.       event.stopPropagation();
  3005.     }
  3006.   },
  3007.   
  3008.   // The object registered with the sbIPlaylistSource interface acts 
  3009.   // as a template for instances bound to specific playlist elements
  3010.   Duplicate: function()
  3011.   {
  3012.     var obj = {};
  3013.     for ( var i in this )
  3014.     {
  3015.       obj[ i ] = this[ i ];
  3016.     }
  3017.     return obj;
  3018.   },
  3019.   
  3020.   SetPlaylist: function( playlist )
  3021.   {
  3022.     this.m_Playlist = playlist;
  3023.   },
  3024.   
  3025.   QueryInterface : function(aIID)
  3026.   {
  3027.     if (!aIID.equals(Components.interfaces.sbIPlaylistCommands) &&
  3028.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  3029.         !aIID.equals(Components.interfaces.nsISupports)) 
  3030.     {
  3031.       throw Components.results.NS_ERROR_NO_INTERFACE;
  3032.     }
  3033.     
  3034.     return this;
  3035.   }
  3036.  
  3037. }
  3038.  
  3039.  
  3040. // Register the download commands at startup if we know what the download table is.
  3041. aDeviceManager = Components.classes["@songbird.org/Songbird/DeviceManager;1"].createInstance(Components.interfaces.sbIDeviceManager);
  3042. if (aDeviceManager)
  3043. {
  3044.   aDownloadDevice = aDeviceManager.GetDevice('Songbird Download Device');
  3045.   if (aDownloadDevice)
  3046.   {
  3047.     SBDownloadCommands.m_Device = aDownloadDevice;
  3048.     var guid = aDownloadDevice.GetContext('');
  3049.     var table = "download"; // aDownloadDevice.GetTransferTableName('');
  3050.     var source = new sbIPlaylistsource();
  3051.     try
  3052.     {
  3053.       source.RegisterPlaylistCommands( guid, table, "download", SBDownloadCommands );
  3054.     }
  3055.     catch ( err )
  3056.     {
  3057.       alert( "source.RegisterPlaylistCommands( " + guid+ ", " + table+ " );\r\n" + err )
  3058.     }
  3059.   }
  3060. }
  3061.  
  3062. // END
  3063.  
  3064. }
  3065. catch ( err )
  3066. {
  3067.   alert( err );
  3068. }
  3069.  
  3070. // alert( "success!" );